1 简单粗暴
线程与锁模型其实是对底层硬件运行过程的形式化。这既是它的优点也是它的缺点。
2 内存和互斥模型
2.1 创建线程
java中,并发的基本单元是线程,线程之间通过共享内存进行通信。
多线程版本Hello World
public class HelloWorld{
public static void main(String[] args){
Thread myThread = new Thread(){
public void run(){
System.out.println("Hello from new thread");
}
};
myThread.start();
Thread.yield();
System.out.println("Hello from main thread");
try{
// 等待myThread线程结束
myThread.join();
}catch(Exception e){
e.printStackTrace();
}
}
}
Thread.yield( )方法:
使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。
join方法:
阻塞所在线程,等调用它的线程执行完毕,再向下执行
第一把锁
public class Counting{
public static void main(String[] args) throws InterruptedException{
class Counter{
private int count = 0;
public void increment(){++count;}
public int getCount(){return count;}
}
final Counter counter = new Counter();
class CountingThread extends Thread{
public void run(){
for(int x=0;x<1000; ++x){
counter.increment();
}
}
}
CountingThread t1= new CountingThread();
CountingThread t2 = new CountingThread();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(counter.getCount());
}
}
如果不对其进行加锁的话,最后的输出结果会在2000和小于2000之间。
如果把 自增的方法改为
public synchronized void increment(){++count;}
就能保证最后结果为2000。(但其中有一个诡异的bug)
诡异的内存
public class Puzzle{
static boolean answerReady = false;
static int answer = 0;
static Thread t1 = new Thread(){
public void run(){
answer = 42;
answerReady = true;
}
};
static Thread t2 = new Thread(){
public void run(){
if(answerReady){
System.out.println(answer);
}else{
System.out.println("No");
}
}
};
public static void main(String[] args) throws Exception{
t1.start();
t2.start();
t1.join();
t2.join();
}
}
运行结果
这里还有一种可能的结果就是输出为0 。
原因如下:
- 编译器的静态优化可以打乱代码的执行顺序。
- JVM的动态优化也会打乱代码的执行顺序。
- 硬件可以通过乱序执行来提高性能。
因此,我们需要一个标准来明确告诉我们,可能发生的副作用,这就是内存模型。
内存可见性
java内存模型定义了何时一个线程对内存的修改对另一个线程可见。基本原则是:如果读线程和写线程不进行同步,就不能保证可见性。
除了上面提到的对象内置锁的同步方法,其他方法包括:开始一个线程并通过join检查线程是否已经终止;使用java.util.concurrent提供的工具包。
多把锁
用多把锁不仅会让运行速度变慢,还可能会导致死锁。
相关阅读:
内存模型: http://blog.csdn.net/suifeng3051/article/details/52611310
volatile和 synchronized区别 http://blog.csdn.net/suifeng3051/article/details/52611233
详解 volatile http://www.importnew.com/18126.html
双重检查 http://blog.csdn.net/dl88250/article/details/5439024
用内部类和双重检查实现单例 http://blog.csdn.net/android_freshman/article/details/51029031