##不使用stop方法停止线程
stop是一个过时的方法。Thread类的stop方法会根据线程状态来判断是终结线程还是设置线程为不可运行的状态,对于未启动的线程(线程状态为NEW)来说,会设置其标志位为不可启动,而其他的状态则是直接停止。
在新的jdk中如果当时线程的状态不是NEW,则会抛出IllegalThreadStateException异常。
stop会直接关闭所有的子线程并不保证子线程的逻辑完整性。
##使用线程异常处理器提升系统的可靠性
在jdk1.5之后添加一个setUncaughtExceptionHandler方法,实现了线程异常捕捉和处理。构建高可用的服务需要我们在出现异常的时候捕捉异常,并重启一个新的线程进行工作。在生产环境中我们需要注意以下三个比较重要的问题:

  • 共享资源锁定
    如果异常产生的原因是资源被锁定,自动重启应用只会增加系统的负担,无法提供不间断的服务。例如一个即时通信服务器(XMPP server)出现信息不能写入的情况,即使重启服务也无法解决问题,对此最好的解决方法就是停止所有的线程释放资源。
  • 脏数据引起的系统逻辑混乱
    异常的产生中断了正在执行的业务逻辑,特别是如果正在执行一个原子操作(像即时通信服务器中的用户验证和签到这两个事情因该在同一个操作中处理,不允许出现验证成功但签到不成功的情况),但如果此时抛出了运行期异常就可能会破坏正常的业务逻辑,例如如果用户的验证通过了,但是签到不成功的情况,在这情况下应该重启应用服务器,虽然可以提供服务但是对部分用户则产生了逻辑异常。
  • 内存溢出
    线程异常了,但由于该线程创建的对象并不会马上回收,如果在重新启动新的线程在创建一批对象,特别是加入了场景接管,就非常危险了,例如通过即时通信服务重启一个线程必须保证原在线用户的透明性(用户不会察觉服务的重启),在这种情况下就需要在线程启动初始化的时候加载大量对象以保证用户的状态信息,但是如果线程反复重启很可能引起OutOfMemory内存泄漏问题。

##volatile不能保证数据的同步性
volatile只能保证工作内存中的数据是从主内存中读取的最新的值,但是并不能保证数据的同步性。
(1)第一个时间片段
A线程获得执行机会,因为有关键字volatile修饰,所以它从主内存中获得count的最新值998,接下来的事情又分为两种类型:
如果是单CPU,此时调度器暂停A线程执行,出让执行机会给B线程,于是B线程也获得了count的最新值998。
如果是多CPU,此时线程A继续执行,而线程B也同时获得count的最新值998。
(2)第二个时间片段
如果是单CPU, B线程执行完加1动作(这是一个原子处理),count的值为999,由于是volatile类型的变量,所以直接写入主内存,然后A线程继续执行,计算的结果也是999,重新写入主内存中。
如果是多CPU, A线程执行完加1动作后修改主内存的变量count为999,线程B执行完毕后也修改主内存中的变量为999。
这两个时间片段执行完毕后,原本期望的结果为1000,但运行后的值却为999,这表示出现了线程不安全的情况。这也是我们要说明的:volatile关键字并不能保证线程安全,它只能保证当线程需要该变量的值时能够获得最新的值,而不能保证多个线程修改的安全性。
##异步运算考虑使用Callable接口
多线程应用实现的方式有三种:
1、 继承Thread类
2、 实现Runnable接口
3、 实现callable接口
实现callable接口表示他是一个可调度的任务,需要调用执行器Executor来执行。callable允许抛出异常以及允许有返回值。
##Lock和Synchronized的区别

  • Lock(显式锁)
    显式锁是对象级别的锁,是跟随对象的,简单的说把Lock定义为多线程类的私有属性是起不到资源互斥作用的,除非把Lock定义为所有线程的共享变量。
    • Lock锁支持更细粒度的锁控制
    • Lock是无阻塞锁
      当线程A持有锁的时候,线程B也期望获得锁,此时如果程序中使用的是显式锁则线程B为等待状态(在通常情况中也认 为该线程被阻塞了),若使用的是内部锁则为阻塞状态。
    • Lock可以实现公平锁
      什么叫非公平锁呢?当一个线程A持有锁,而线程B、C处于阻塞(或等待)状态时,若线程A释放锁,JVM将从线程B、C中随机选择一个线程持有锁并使其获得执行权,这叫做非公平锁(因为它抛弃了先来后到的顺序);若JVM选择了等待时间最长的一个线程持有锁,则为公平锁(保证每个线程的等待时间均衡)。需要注意的是,即使是公平锁,JVM也无法准确做到“公平”,在程序中不能以此作为精确计算。

显式锁默认是非公平锁,但可以在构造函数中加入参数true来声明出公平锁,而synchronized实现的是非公平锁,它不能实现公平锁。
- Lock是代码级的,synchronized是JVM级的
Lock是通过编码实现的,synchronized是在运行期由JVM解释的,相对来说synchronized的优化可能性更高,毕竟是在最核心部分支持的,Lock的优化则需要用户自行考虑。
显式锁和内部锁的功能各不相同,在性能上也稍有差别,但随着JDK的不断推进,相对来说,显式锁使用起来更加便利和强大,在实际开发中选择哪种类型的锁就需要根据实际情况考虑了:灵活、强大则选择Lock,快捷、安全则选择synchronized。
##使用CountDownLatch协调子线程
CountDownLatch的作用是一个计数器,每个线程在运行完毕之后都会执行countDown表示自己已经结束,这对于多个子任务的计算特别有效,比如一个异步任务需要拆分成10个子任务执行,主任务必须知道子任务是否完成,所有子任务完成后才能进行合并运算,从而保证了一个主任务的逻辑正确性。
##CycliBarrier让多线程个齐步走
CyclicBarrier关卡可以让所有线程全部处于等待状态(阻塞),然后在满足条件的情况下继续执行,这就好比是一条起跑线,不管是如何到达起跑线的,只要到达这条起跑线就必须等待其他人员,待人员到齐后再各奔东西,CyclicBarrier关注的是汇合点的信息,而不在乎之前或之后做何处理。