Java多线程编程的注意点
l 多线程下,如果存在共享数据(如全局Map等),需要考虑线程安全;
l synchronized (obj) { … } 语句块加锁的范围要尽可能小;
l synchronized (obj) { … } 语句块中的代码一定不能有可能会挂死的语句或可能会长时间不返回的语句;(案例:在同步语句块中加入了操作db的语句,因为db出现死锁,导致线程挂死,无法退出synchronized语句块,其它线程全部阻塞,最终整个平台僵死);
l 虽然Java内存模型保证存取操作的原子性,但long和double类型除外,除非声明为volatile ['vɑlətl] ;
l 示例:多个线程并发去修改一个long变量,然后由一个线程去输出该long变量的结果,最终输出的结果中有很多值是随机的;
即定义静态的long double类型的变量多线程操作,必须同步synchronized处理,或者使用volatile声明同步
l 有兴趣的,可以把long类型修改为int,看是否会出现这种情况;
l 有兴趣的,还可以在long类型前加上volatile关键字,再测试一下结果如何;
l Java中,同一个线程可以对一个对象加N次锁;
synchronized (obj)
{
synchronized (obj)
{
}
}
synchronized(obj) 语句块的在JVM内部的实现:
某线程在执行到synchronized(obj) 语句块时,JVM内部对obj是维护着一个计数器的,当计数器为0,说明当前没有线程对obj加锁,则当前线程可以对obj加锁,同时计数器加1;如果当前计数器不为0,则JVM会先判断当前线程是不是就是已经对obj加锁的线程,如果不是,则该线程需要等待obj锁被其它线程释放;如果是,则obj的计数器还会被加1;
某线程退出一个synchronized(obj) 语句块,则obj的计数器减一,直到obj的计数器变成0,当前线程才完成释放对obj锁的占用;