首先演示一下并发性(关于并发性的解释建议看MSDN中.net部分相关的解释、感觉微软解释的很详细、不仅说了并发性 还有其他可能由多线程引发其他问题)
1 public class ThreadDemo2 { 2 public static void main(String[] args) { 3 TestThread1 thread = new TestThread1(); 4 Thread t1 = new Thread(thread); 5 Thread t2 = new Thread(thread); 6 7 t1.start(); 8 t2.start(); 9 } 10 } 11 12 class TestThread1 implements Runnable { 13 private int i = 0; 14 15 @Override 16 public void run() { 17 while (i < 50) { 18 try { 19 Thread.sleep(500); // 模拟CPU切换线程 20 } catch (InterruptedException e) { 21 e.printStackTrace(); 22 } 23 System.out.println(i++); 24 } 25 } 26 }
上面的代码 在命令行只会输出50个数字、而不是和我们预期一样的 两个线程各输出50个数字、此时将线程类改成下面的形式
1 class TestThread1 implements Runnable { 2 // private int i = 0; 3 4 @Override 5 public void run() { 6 int i = 0; 7 while (i < 50) { 8 try { 9 Thread.sleep(500); // 模拟CPU切换线程 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } 13 System.out.println(i++); 14 } 15 } 16 }
就会和一开始预期的一样出现100个数字、当然出现数字是不具有确定性的、
此时再举一个例子——单例模式、如下:
1 class Singleton { 2 private static Singleton obj; 3 4 private Singleton() { 5 } 6 7 public static Singleton getInstance() { 8 if (obj == null) 9 obj = new Singleton(); 10 return obj; 11 } 12 }
单例模式本意是希望只生成一个类的实例对象、但是很遗憾、单例模式这样的写法、并不是线程安全、也就是说在多线程的环境下有可能会产生一个以上的实例对象、具体代码如下:
1 public class ThreadDemo3 { 2 public static void main(String[] args) { 3 TestThread2 t1 = new TestThread2(); 4 TestThread2 t2 = new TestThread2(); 5 TestThread2 t3 = new TestThread2(); 6 7 t1.start(); 8 t2.start(); 9 t3.start(); 10 11 /* 12 * 我这的输出结果如下、 13 * Singleton@3ce53108 14 * Singleton@6af62373 15 * Singleton@6af62373 16 */ 17 } 18 } 19 20 class Singleton { 21 private static Singleton obj; 22 23 private Singleton() { 24 } 25 26 public static Singleton getInstance() { 27 if (obj == null) 28 obj = new Singleton(); 29 return obj; 30 } 31 } 32 33 class TestThread2 extends Thread { 34 @Override 35 public void run() { 36 System.out.println(Singleton.getInstance()); 37 } 38 }
在我的输出结果中、很显然t2/t3获得的是同一个对象(结果具有不确定性、你们的测试结果也许会出现三个对象相同、请多运行几次)、但是t1获得的是另一个对象、这显然就违背了单例模式的初衷、
之所以会出现我们不希望的情况 是因为在第一个线程在判断了if(obj==null)之后 准备去构造对象(但是还没有构造)的时候、第二个线程调用了方法、并判断obj是否等于null、此时因为第一个线程还没有构造对象、所以第二个线程也进入了if语句块内、因此 出现了可能会构造两个不同的对象、
在JDK1.5之前(不包括1.5)synchronized关键字来保证例子中单例模式的正确性、即这样定义单例模式
1 class Singleton { 2 private static Singleton obj; 3 4 private Singleton() { 5 } 6 7 public synchronized static Singleton getInstance() { 8 if (obj == null) 9 obj = new Singleton(); 10 return obj; 11 } 12 }
具体synchronized关键字的用途和说明可以参看JDK文档或者百度、我就不介绍了、(重点就搞清楚一个叫做锁(lock)或者叫监视器(Monitor)的东西即可)
嗯 就记录这么多、下次自己应该能看懂、 |