[首页]
[文章]
[教程]
首页
Web开发
Windows开发
编程语言
数据库技术
移动平台
系统服务
微信
设计
布布扣
其他
数据分析
首页
>
编程语言
> 详细
Java多线程笔记
时间:
2015-07-12 17:30:51
阅读:
343
评论:
0
收藏:
0
[点我收藏+]
1、使用new Thread(runnableObj)方式,而非继承自Thread。
对于耗时的任务,应放到线程中执行
调用new Thread(runnable).start()方法启动线程,将会在线程中调用对应的runnalbe.run方法
2、中断线程的方式:调用interrupt方式,会置位线程中断状态。检查这个中断位可判断线程是否被中断:Thread.currentThread().isInterrupted().
currentThread可用于获取当前线程。
sleep方法会清除中断状态并抛出InterruptedException。
interrupt()会向线程发中断请求,并将中断状态置为true。
interrupted()方法会检测是否线程被中断了,如果是会清除中断状态。
线程状态:New,Runnable可运行(调用start后的状态,正在执行的线程状态以及等待执行的都是可运行),Blocked被阻塞,Waitting,Timed waiting计时等待,Terminated。
被阻塞的情况:1、等待锁被释放;2、当线程等待另一个线程通知调度器一个条件时,它自己进入等待状态;方法带有超时参数,超时时会进入计时等待状态。如Thread.sleep,Object.wait(),Thread.join(),Lock.tryLock(),Condition.await()
3、join()等待终止指定的线程,join(long mills)等待指定线程死亡或经过指定的毫秒数;
Thread.State getState()获取线程的状态
4、线程继承自父线程的优先级。用setProperty调整优先级,取值0~10,值越大优先级越高。
static void yield()此方法导致当前执行线程处于让步状态,有同优先级线程存在时,会优先执行。
5、this.setDaemon(true)使线程转换为守护线程,此方法必须在线程启动前调用。守护线程的用途是为其他线程提供服务。当只剩下守护线程时,虚拟机退出。守护线程应该永远不要去访问固定资源,如文件、数据库,因为它在任何时候都可能在一个执行过程中发生中断。
6、线程的run不能抛出被检测的异常。未被检测的异常会导致线程终止,线程死亡前异常会被传递到一个用于未捕获异常的处理器。该处理器实现了Thread.UncaughtExcetptionHandler接口。没安装默认处理器的话,默认处理器为空。不为独立的线程安装处理器,其处理器就是ThreadGroup对象
不要在Catch语句中处理可被传递的异常。
javap -c -v Bank 用于对Bank.class进行反编译
7、采用synchronized保证代码块的并发访问。
ReentrantLock是一个锁对象,可用于控制并发。在一个公共访问代码中声明一个锁对象。在try之前获得锁,finally里释放锁。而非将锁对象作为线程的成员。
锁是可重入的,线程可以重复获取已持有的锁。锁保持一个持有计数,在临界区内调用其他方法时,计数加1,所调用的方法退出时,锁减1.
留心临界区的异常处理,不要因异常而导致跳出临界区。
8、条件对象用于线程等待某个条件满足时执行操作。单纯的锁无法满足这种场景。
一个锁可以关联多个条件变量Condition。bankLock.newCondition()创建锁关联的条件变量。在临界区内,while(condition no statisfy)condition.await();在循环体中调用是必须的。 通过调用条件变量中的await方法会进入该条件的等待集,阻塞,等待另一个线程调用同一条件上的signalAll方法(会解除所有等待这一条件的线程的阻塞,使得被解除阻塞的线程可以在当前线程退出阻塞之后,通过竞争实现对象的访问)。signal()方法则是随机解除一个阻塞的线程,这个方式需保证被解除阻塞的线程可以执行,否则会造成死锁。
每个条件对象管理那些已经进入了被保护的代码段,但还不能运行的线程。
每个对象内都有一把锁,要调用synchronized声明的对象成员方法,必须事先获得内部的对象锁。
内部的对象锁只有一个关联的条件对象,wait会将线程添加到等待集中,notify/notifyAll会解除等待线程的阻塞状态。只能在synchronized内部使用wait和notify方法实现条件对象等待某个条件实现的功能。模式与await和signal相似。
一般不要用synchronized和Condition,优先用synchronized。
线程有本地缓存和寄存器,可以暂存内存中的值。如果使用锁来执行并发访问共享变量,编译器被要求在必要的时候刷新本地缓存(更新共享变量在本地的值)来保持锁的效应。
volatile为同步访问提供了免锁机制,但是不保证原子性。如果共享变量除了赋值外,不完成其他操作,可以将其声明为volatile。
atomic对象可以原子方式对变量做加减。
9、public static final ThreadLocal<SimpleDateFormat> dataFormat=
new ThreadLocal<SimpleDateFormat>(){
protect SimpleDateFormat initialValue(){
return new SimpleDateFormat("yyyy-MM-dd");
}
}
10、锁超时: if(myLock.tryLock(100,TimeUnit.MILLISECONDS)){...} 超时时抛出InterruptedException,可用于打破死锁。
myCondition.await(100,TimeUnit.MILLISECONDS)
11、读线程多写线程少用ReentrantReadWriteLock。
private rwLock = new ReentrantReadWriteLock();
rLock=rwLock.readLock();该所被所有读线程共用,会排斥写操作在读之前用rLock.lock();结束后用rLock.unlock();
wLock=rwLock.writeLock();排斥其他的读操作和写操作n。在写之前用wLock.lock();结束后用wLock.unlock();
12、阻塞队列BlockingQueue(这个有几种继承类:LinkedBlockingQueue, LinkedBlockingDeque, ArrayBlockingQueue)就是一个生产者消费者模型中的用于存放共享数据的队列。该队列有考虑生产者消费者间的并发操作,处理生产者消费者速度的负载平衡。用offer添加一个元素、poll移出并返回队头、peek返回队头元素(这三种操作可指定操作的超时时间)。
PriorityBlockingQueue优先队列。
13、线程安全集合:阻塞队列、ConcurrentHashMap, ConcurrentSkipListMap, ConcurrentSkipListSet(这两个是线程安全的有序集,需事先Comparable接口), ConcurrentLinkedQueue. 这些集合的size()内部需要通过遍历来确定集合大小,这与一般的集合不同。
这些集合返回的是弱一致性的迭代器,不一定能返回被修改后的值,但不会将同一个值返回两次,不会抛出ConcurrentModificationException。
ConcurrentHashMap<E>(int initialCapacity, float loadFactor, int concurrentLevel);中参数是指定集合的初始容量,默认为16.concurrentLevel是并发写者线程的估计数目,表明可供多达16个写进程同时写,多了会阻塞剩下的线程。
ConcurrentHashMap.putIfAbsent(k,v)是在该键不存在时插入kv对,否则返回键k对应的值。
写数组的拷贝:
CopyOnWriteArrayList和CopyOnWriteArraySet。写线程对底层数据做修改。如果读线程数大于写线程数,则这类集合很适合。读写可不用同步就可保持一致性。
任何集合类通过同步包装器可变为线程安全的,通过给集合加入锁来实现的,这不推荐使用,因为还是需要在访问的代码中加入synchronized(synchashMap){...},推荐使用ConcurrentXXX集合:
List<E> syncArrayList = Collections.synchronizedList(new ArrayList<E>());
HashMap<K,V> syncHashMap = Collections.synchronizedMap(new HashMap<K,V>());
对于经常被修改的数组列表,采用synchronized(arrayList){}会比CopyOnWriteArrayList性能更好。
14、回调Callable和Future。 Runnalbe是无返回值无参数的异步方法,Callable和Future有返回值。Callable<E>{ E call();}只有一个方法返回值类型为E的call().
Future保存了异步计算结果,其get(long timeout,TimeUnit)可指定超时时间,超时时中断。如果Future还在执行,则isDone()返回false。cancle()方法可取消该运算。
FutureTask包装器,可将Callable转化为Future何Runnable。
Callable<Integer> myCompution=..;
FutureTask<Integer> task= new FutureTask<Integer>(myCompution);//构造一个既是Future又是Runnable的对象。
Thread t= new Thread(task);
t.start();
...
Integer result=task.get();//对get调用会阻塞直到有可获得的结果或者超时为止。
15、执行器Executor
如果程序中有大量生命期很短的线程,最好使用线程池。线程池中包含了许多准备运行的空闲线程。将Runnable交给线程池,就会有一个线程调用Runnable.run()。run退出时线程又回到线程池等待下一次运行。
使用线程池可减少并发线程数。
Executor中有许多静态方法可用于构建线程池:newCachedThreadPool空闲线程被保存60s;newFixedThreadPool固定线程数且空闲线程一直保存,如果任务数大于线程数,未得到执行的任务会放到队列中等待空闲线程可用;newSingleThreadPool只有一个线程,用于顺序执行。这些方法返回实现了ExecutorService接口的ThreadPoolExecutor对象。
可用ExecutorService接口中的Future<?> submit(Runnable,T result);Future<?>submit(Callable<T> Task)方法提交Runnable和Callable对象给ExecutorService。
线程池用完后调用shutdown()关闭线程池。
步骤:
a、Executors.newFixedThreadPool()
b、submit提交Runnable或Callable对象;
c、获取Future对象result,并调用result.get();
d、关闭线程池shutdown()
15、预定执行(定时任务)
ScheduledExecutorService接口中有为预定执行或重复执行的任务设计的方法。
ScheduledExecutorService ss=Executors.newScheduledThreadPool();
schedule(Callable/Runnable,initDelayTime,TimeUnit);
scheduleAtFixedRate(Callable/Runnable,initDelayTime,long period,TimeUnit);//每隔period执行一次
16、控制任务组
Executor可用于控制一组相关任务。
invokeAny:多个任务执行,只要有一个执行完成就可以结束了。
invokeAll:多个任务执行,所有任务都执行完成才可以结束。使用方式如下:
List<Callable<T>> tasks=...;
List<Future<T>> results=executor.invokeAll(tasks);
for(Future<T>res:results){//顺序遍历在第一个任务耗时很长的情况下会花很多时间进行等待,推荐用ExecutorCompletionService按结果产生顺序进行保存,更有效
processFuturer(result.get());
}
17、fork-join框架(大任务划分为小任务,并行执行后merge)
RecursiveTask用于有计算结果返回,RecursiveAction用于无计算结果返回。二者的compute用于生成并调用子任务并合并结果。
class Counter extends RecursiveTask<Integer>{//分治算法
protect Integer compute(){
if(to-from<THRESHOLD){直接执行(单任务)}
else{
int mid=(low+high)>>1;
Counter first=new Counter(from,mid);//拆分子任务
Counter second=new Counter(mid+1,high);
invokeAll(first,second);//调度所有子任务
return first.join()+second.join();//合并结果
}
}
}
main(){
ForkJoinPool pool=new ForkJoinPool();
pool.invoke(counter);
System.out.println(counter.join());
}
18、同步器
提供了实现线程间相互合作的类:
CyclicBarrier:等待一定数目的线程都到达一个公共屏障,在执行一个处理屏障的动作。
CyclicBarrier barrier=new CyclicBarrier(numThreads,barrierAction);//当numThreads个线程都到达屏障时执行barrierAction
Runnable{
public void run(){
doSomething...
barrier.await();//等待直到屏障打开,可设置超时时间,超时时抛异常,会导致其他等待await的线程都抛BrokenBarrierException异常。
...
}
}
CountDownLatch:允许等待直到计数器为0。用于当一个或多个线程需等到指定数目事件发生时。这是一次性的,只可用一次。
Exchanger:允许两个线程在要交换对象准备好时交换对象。两个线程在同一个数据结构的两个不同实例上,一个向实例添加数据,另一个用于清除数据
Semaphore:允许线程等待直到被允许执行为止。用于限制访问资源的线程数。
信号量管理了许多permits,用于限制通过的线程数量。信号量仅维护一个计数。其他线程通过调用release()释放许可permits。
SynchronousQueue:允许一个线程把对象交给另一个线程。在没显式同步时,两个线程将一个对象从一个线程传到另一个线程。
版权声明:本文为博主原创文章,未经博主允许不得转载。
Java多线程笔记
原文:http://blog.csdn.net/cklsoft/article/details/46850817
踩
(
0
)
赞
(
0
)
举报
评论
一句话评论(
0
)
登录后才能评论!
分享档案
更多>
2021年09月23日 (328)
2021年09月24日 (313)
2021年09月17日 (191)
2021年09月15日 (369)
2021年09月16日 (411)
2021年09月13日 (439)
2021年09月11日 (398)
2021年09月12日 (393)
2021年09月10日 (160)
2021年09月08日 (222)
最新文章
更多>
2021/09/28 scripts
2022-05-27
vue自定义全局指令v-emoji限制input输入表情和特殊字符
2022-05-27
9.26学习总结
2022-05-27
vim操作
2022-05-27
深入理解计算机基础 第三章
2022-05-27
C++ string 作为形参与引用传递(转)
2022-05-27
python 加解密
2022-05-27
JavaScript-对象数组里根据id获取name,对象可能有children属性
2022-05-27
SQL语句——保持现有内容在后面增加内容
2022-05-27
virsh命令文档
2022-05-27
教程昨日排行
更多>
1.
list.reverse()
2.
Django Admin 管理工具
3.
AppML 案例模型
4.
HTML 标签列表(功能排序)
5.
HTML 颜色名
6.
HTML 语言代码
7.
jQuery 事件
8.
jEasyUI 创建分割按钮
9.
jEasyUI 创建复杂布局
10.
jEasyUI 创建简单窗口
友情链接
汇智网
PHP教程
插件网
关于我们
-
联系我们
-
留言反馈
- 联系我们:wmxa8@hotmail.com
© 2014
bubuko.com
版权所有
打开技术之扣,分享程序人生!