码迷,mamicode.com
首页 > 编程语言 > 详细

Java多线程

时间:2016-07-29 18:34:29      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:

线程

进程与线程的本质区别在于每个进程拥有自己的一整套变量,而线程则共享数据。

Thread.sleep(long)就是用于暂停当前线程,没有必要Thread.currentThread().sleep(long)。 

Runnable接口本身代表一个任务,然后需要启动一个Thread来执行这个任务。

虽然可以直接构造一个Thread的子类,在run方法中实现任务功能,但不推荐这么做。应该从运行机制上减少需要并行运行的任务数量。如果有很多任务,要为每个任务创建一个独立的线程所付出的代价太大了。可以使用线程池来解决问题。 

不要调用Thread类或Runnable对象的run方法。直接调用run方法,只会执行同一个线程中的任务,而不会启用新线程。应该调用Thread.start方法,这个方法将创建一个执行run方法的新线程。 

守护线程的唯一用途是为其他线程提供服务。当只剩下守护线程时,虚拟机就退出了。

线程中断

当在一个被阻塞的线程(调用sleep或wait)上调用interrupt方法时,阻塞调用将会被InterruptedException异常中断,并清除线程的中断状态。 

Thread.intertupt()方法不会中断一个正在运行的线程。这一方法实际上完成的是,设置线程的中断标示位,在线程受到阻塞的地方(如调用sleep、wait、join等地方)抛出一个异常InterruptedException,并且中断状态也被清除,这样线程就得以退出阻塞的状态。 

如果在每次工作迭代之后都调用sleep方法(或者其他的可中断方法),isInterrupted检测既没有必要也没有用处。原因是:如果在中断状态被置位时调用sleep方法,它不会休眠,而会清除这一状态并抛出InterruptedException。这样就没有必要每次检查中断状态,而间接通过sleep检查了,通过捕获InterruptedException来进行后续处理。 

Object.wait, Thread.sleep方法,会不断的轮询监听 interrupted 标志位,发现其设置为true后,会停止阻塞并抛出 InterruptedException异常。 

中断一个线程不过是引起它的注意,被中断的线程可以决定如何响应中断。处于死锁状态的线程是无法被中断的。

线程状态

线程有6种状态:New(新创建)、Runnable(可运行)、Blocked(被阻塞)、Waiting(等待)、Timed Waiting(计时等待)、Terminated(被终止)。 

当一个线程试图获取一个内部对象锁(而不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程进入阻塞状态。当所有其他线程释放该锁,并且线程调度器允许本线程持有它的时候,该线程将变成非阻塞状态。 

被阻塞状态与等待状态是有很大不同的。一旦一个线程调用await方法,它进入该条件的等待集。当锁可用时,该线程不能马上解除阻塞。相反,它处于阻塞状态,直到另一个线程调用同一条件上的signalAll方法时为止。

线程同步

Java中每一个对象都有一个内部锁。如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。并且该锁还有一个内部条件。静态方法也可以使用synchronized,如果调用这种方法,该方法获得相关的类对象的内部锁。 

ReentrantLock可重入锁是指锁可以被线程重复使用,单个线程最大可以重复使用2147483647次。 

ReentrantLock默认就是常规锁,也可以选择使用公平锁。公平锁会倾向于根据线程等待时间来选择应该哪个线程获得锁,但并不保证一定这样。 

volatile(不稳定的)关键字为实例域的同步访问提供了一种免锁机制。如果声明一个域为volatile,那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。volatile变量不能提供原子性,也就是说这个关键字通知了方法在访问该变量的时候需要更新缓存获取最新数据,但没有办法来保证内部操作的时候不受其他线程影响。 

SimpleDateFormat类不是线程安全的,所以在类中使用一个私有的域来保存一个公用的SimpleDateFormat是错误的,而每次进行日期格式转化都new出来新的Format类的代价又很高。应该使用ThreadLocal来包装SimpleDateFormat对象,这样每个转化线程持有自身的Format对象不会有并发问题。个人认为前提是线程是需要复用的,比如使用线程池。否则效果和每次new新的Format对象没有差别。或者如果使用线程池,即便不是用ThreadLocal,而保证每个线程使用自己独立的Format对象也可以。 

阻塞队列&线程安全集合

使用队列,可以安全地从一个线程向另一个线程传递数据。

可以使用同步包装器来把不是线程安全的ArrayList、HashMap等包装成线程安全的,如果在另一个线程可能进行修改时要对集合进行迭代,仍然需要使用客户端锁定。最好使用java.util.concurrent包中定义的集合,不是用同步包装器。 

其它

Runnable封装一个异步运行的任务,是一个没有参数和返回值的异步方法。Callable与Runnable类似,但是有返回值。Future用于保存异步计算的结果。 

执行器(Executor)类用于构建线程池。

ScheduledExecutorService是一种允许使用线程池机制的java.util.Timer的泛化。 

Fork-Join框架适用于计算密集型,任务可分级的计算。 

同步器中有CyclicBarrier、CountDownLatch、Exchange、Semaphore、SynchronousQueue。目前项目只使用过CountDownLatch和Semaphore,CountDownLatch用于将请求调用和结果返回进行异步处理,Semaphore用于在后台系统出现故障时限制并发访问量。

参考

Java核心技术(卷1)

http://www.cnblogs.com/onlywujun/p/3565082.html

Java多线程

标签:

原文地址:http://www.cnblogs.com/jiaoqq/p/5719086.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!