随着多核时代的到来,JAVA类库提供了更多的并发方面的处理,这里结合《Effective Java》做个总结:
1. 区分线程操作是并发还是为了通讯,不仅仅是并发的情况需要同步。
JAVA 对于32位以下(依赖于硬件)可以表示的类型,也就是除了double和long的,都是可以通过原子操作完成的,但是当一个线程改变了这个变量时,并不立即在另外一个线程里可以看到,这依赖于线程的通讯。
看如下例子:
/**
* @description 如下这种写法,在我的虚拟机上可以正常停止,但是如果虚拟机做过优化,则不一定能正确结束
* @author job
* @date 2010-8-16 下午08:48:25
* @version 1.0
*/
public class StopThread {
public static Boolean stopRequest = Boolean.FALSE;
public static void main(String[] args) throws InterruptedException {
Thread backThread = new Thread(new Runnable() {
public void run() {
int i= 0;
long start = System.nanoTime();
while(!stopRequest){
System.out.println(i);
i++;
}
long totalTime = System.nanoTime()-start;
System.out.println("time:"+totalTime);
}
});
backThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequest = true;
}
}
运行结果为 time:997494594
可以看到在我的虚拟机上可以正常的通讯,但是在有些虚拟机上会将循环代码优化为
if(!stopRequest){
while(true)
i++;
}
这个就叫活性失败。为什么主线程和子线程需要通讯呢,这个和JMM (JAVA的内存模型)有关,JAVA给不同的线程分配了不同的内存,叫工作内存,工作内存之间互相使不可见的,只能通过主存进行通讯。可以有如下两种方法来进行同步
2. synchronized 同步,这个是在不同线程之间通过 wait 和notify事件进行同步,效率不高。
class SyncStopThread {
public static Boolean stopRequest = false;
private static synchronized void requestStop(){
stopRequest= true;
}
private static synchronized boolean stopRequest(){
return stopRequest;
}
public static void main(String[] args) throws InterruptedException {
Thread backThread = new Thread(new Runnable() {
public void run() {
int i= 0;
long start = System.nanoTime();
while(!stopRequest()){
System.out.println(i);
i++;
}
long totalTime = System.nanoTime()-start;
System.out.println("time:"+totalTime);
}
});
backThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop() ;
}
}
3. 使用volatile 进行不稳定变量的声明。
volatile的语义, 其实是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我.因此, 当多核或多线程在访问该变量时, 都将直接操作主存, 这从本质上, 做到了变量共享.效率更高
class VolatileStopThread {
public static volatile Boolean stopRequest = false;
public static void main(String[] args) throws InterruptedException {
Thread backThread = new Thread(new Runnable() {
public void run() {
int i= 0;
long start = System.nanoTime();
while(!stopRequest){
System.out.println(i);
i++;
}
long totalTime = System.nanoTime()-start;
System.out.println("time:"+totalTime);
}
});
backThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequest =true ;
}
}
注意:volatile 只对原子性的操作起作用,如果是序列号的增加 i++这种操作,是不能通过volatile 来避免并发问题的,两个线程有可能同时读到一个值,进行操作,然后获得了相同的序列号,这种就是 安全性失败。最好的方式是使用atomic的类库,这个下篇博客详细介绍。
4. 总结:对于线程之间共享变量,有几个原则可以借鉴
(1)尽量将可变变量保存在线程中
(2)线程安全通讯(安全发布)的几种方法:保存在静态域中,作为初始化的一部分;保存在volatile、final或者通过正常锁定的域中,也可以放到concurrentMap等并发集合中。
(3)基本上通过volatile 和 atomic 能够解决一般的并发问题。
(4)volatile 适用于仅仅需要通讯,不需要互相排斥操作的情况下:一般来说,子线程和主线程之间是需要通讯的,子线程和子线程对可变参数的处理都是要互相排斥的。
补充同事的一个关于volatile 和atomic的诠释:
volatile 只是将内容放入主存,也就是共享内存,而一般的如果不使用这个声明,那就是放入二级缓存,其它线程可能将这个变量已经更新到主存,就引起脏读,它不能解决 int 和long等占用两个字节的操作,说白了就是:volatile只保证线程同时对存储单元的可见性。但是不保证原子性。要实现原子性,就要使用AUTOMIC。它基于乐观锁,通过循环的方式来不断轮询看是不是有线程更新了这个值。
一般我们的场景都是IO密集型运算,所以才可以做一些并发编程的优化。要是CPU密集型的话,CPU一直很忙,那就没有优化余地了。AUTOMIC这个包也是基于这个考虑才使用乐观并发的方式的。
分享到:
相关推荐
java并发编程pdf文档第二部分:Java并发编程实战.pdf、Java多线程编程核心技术.pdf、实战Java高并发程序设计.pdf
java并发编程实战源码 附有本书所有源码,maven 导入 eclipse或idea
java并发编程艺术java并发编程艺术java并发编程艺术java并发编程艺术java并发编程艺术
JAVA并发编程实践中文版 英文版 原书源码 带书签 java_concurrency_in_practice.pdf 英文版还是不错的,但是中文版的译者典型的没有技术功底,介绍上说什么专家, 翻译的非常差劲,有些句子都不通顺,都不知道自己去...
JAVA并发编程艺术 高清pdf : 1.并发变成的挑战 2. java并发机制的底层实现原理 3. java 内存模型 4. java并发编程基础 5.java中的锁。。。。。。。
深入讲解java并发编程技术,多线程、锁以及java内存模型等
java 并发编程的艺术pdf清晰完整版 源码
java并发编程内部分享PPT
这就是最正宗的《Java 并发编程实战》带目录 用福昕阅读器打开查看特别的清晰
Java 并发编程实战.pdf 目录齐全
《JAVA并发编程实践》随着多核处理器的普及,使用并发成为构建高性能应用程序的关键。Java 5以及6在开发并发程序中取得了显著的进步,提高了Java虚拟机的性能以及并发类的可伸缩性,并加入了丰富的新并发构建块。在...
java并发编程实战 pdf
java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...
java并发编程与实践是java高并发的分析文档,分析并介绍了高并发的解决方案。
62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java...
它选取了Java并发编程中最核心的技术进行讲解,从JDK源码、JVM、CPU等多角度全面剖析和讲解了Java并发编程的框架、工具、原理和方法,对Java并发编程进行了最为深入和透彻的阐述。 《Java并发编程的艺术》内容涵盖...
第一部分 基础知识 第2章 线程安全性 2.1 什么是线程安全性 2.2 原子性 2.2.1 竞态条件 2.2.2 示例:延迟初始化中的竞态条件 2.2.3 复合操作 2.3 加锁机制 2.3.1 内置锁 2.3.2 重入 2.4 用锁来保护状态 ...
JAVA并发编程(阿里巴巴培训资料) Java 并发编程培训(阿里巴巴) ppt 文档。
《JAVA并发编程实践》随着多核处理器的普及,使用并发成为构建高性能应用程序的关键。Java 5以及6在开发并发程序中取得了显著的进步,提高了Java虚拟机的性能以及并发类的可伸缩性,并加入了丰富的新并发构建块。在...