您的位置:首页 > 编程语言 > Java开发

[Java基础]多线程之并发性以及解决方法

2016-02-03 15:08 555 查看
首先演示一下并发性(关于并发性的解释建议看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)的东西即可)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: