[Java基礎]多線程之並發性以及解決方法


首先演示一下並發性(關於並發性的解釋建議看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)的東西即可)

 

嗯 就記錄這么多、下次自己應該能看懂、


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM