Java中的線程--線程范圍內共享數據


  接着學習Java中的線程,線程范圍內的共享數據!

一、線程范圍內的數據共享定義

對於相同的程序代碼,多個模塊在同一個線程中共享一份數據,而在另外線程中運行時又共享另外一份數據。

共享數據中存在的問題,代碼如下:

 1 // A 和 B共享數據data,但是在這種情況下 會存在問題
 2 public class ThreadScopeShareData {
 3 
 4     private static int data = 0;
 5 
 6     public static void main(String[] args) {
 7         for (int i = 0; i < 10; i++) {
 8             new Thread(new Runnable() {
 9                 @Override
10                 public void run() {
11                     data = new Random().nextInt();
12                     System.out.println(Thread.currentThread().getName() + "has put data " + data);
13                     new A().get();
14                     new B().get();
15                 }
16             }).start();
17         }
18     }
19 
20     static class A {
21         public void get() {
22             System.out.println("A from " + Thread.currentThread().getName() + "has put data " + data);
23         }
24     }
25 
26     static class B {
27         public void get() {
28             System.out.println("B from " + Thread.currentThread().getName() + "has put data " + data);
29         }
30     }
31 
32 }

運行結果如下:(好像是有點亂七八糟的感覺)

 1 Thread-3has put data 1233171571
 2 Thread-7has put data -1796246182
 3 Thread-1has put data -609826403
 4 A from Thread-3has put data 1961867182
 5 A from Thread-1has put data 1961867182
 6 Thread-8has put data 2116621494
 7 A from Thread-8has put data 1961867182
 8 Thread-5has put data -609826403
 9 A from Thread-5has put data 1961867182
10 A from Thread-7has put data 1961867182
11 B from Thread-7has put data 1961867182
12 B from Thread-5has put data 1961867182
13 Thread-6has put data -609826403
14 A from Thread-6has put data 1961867182
15 B from Thread-6has put data 1961867182
16 Thread-0has put data 1233171571
17 A from Thread-0has put data 1961867182
18 B from Thread-0has put data 1961867182
19 Thread-9has put data 1961867182
20 A from Thread-9has put data 1961867182
21 B from Thread-9has put data 1961867182
22 B from Thread-1has put data 1961867182
23 Thread-2has put data 1233171571
24 Thread-4has put data 1233171571
25 A from Thread-4has put data 1961867182
26 B from Thread-4has put data 1961867182
27 B from Thread-8has put data 1961867182
28 B from Thread-3has put data 1961867182
29 A from Thread-2has put data 1961867182
30 B from Thread-2has put data 1961867182

解決方案如下,用線程范圍內的變量,當然這個是比較粗糙的解決方案,代碼如下:

 1 public class ThreadScopeShareData {
 2 
 3     private static int data = 0;
 4     // 這個用來存放當前線程內的共享數據
 5     private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
 6 
 7     public static void main(String[] args) {
 8         for (int i = 0; i < 10; i++) {
 9             new Thread(new Runnable() {
10                 @Override
11                 public void run() {
12                     int data = new Random().nextInt();
13                     System.out.println(Thread.currentThread().getName() + "has put data " + data);
14                     threadData.put(Thread.currentThread(), data);
15                     new A().get();
16                     new B().get();
17                 }
18             }).start();
19         }
20     }
21 
22     static class A {
23         public void get() {
24             int data = threadData.get(Thread.currentThread());
25             System.out.println("A from " + Thread.currentThread().getName() + "has put data " + data);
26         }
27     }
28 
29     static class B {
30         public void get() {
31             int data = threadData.get(Thread.currentThread());
32             System.out.println("B from " + Thread.currentThread().getName() + "has put data " + data);
33         }
34     }
35 
36 }

二、JDK中解決線程共享數據(ThreadLocal)

 優化解決方法,更加優雅的代碼,更加人性化的解決方法,使得用戶用起來更加方便,封裝到ThreadLocal中,並且得保證同一個線程,所得到的的是同一份數據!

改造之后的實體對象,代碼如下:

 1 // 改造之后的實體類,封裝創建方法,並且封裝ThreadLocal,來保證同一個線程得到的同一個對象
 2 public class MyThreadScopeData {
 3 
 4     private String name;
 5     private int age;
 6     //private static MyThreadScopeData instance = null;
 7     private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
 8     
 9     private MyThreadScopeData() {
10         
11     }
12     
13     public static /* synchronized */ MyThreadScopeData getThreadInstance() {
14         MyThreadScopeData instance = map.get();
15         if(instance == null) {
16             instance = new MyThreadScopeData();
17             map.set(instance);
18         }
19         return instance;
20     }
21 
22     public String getName() {
23         return name;
24     }
25 
26     public void setName(String name) {
27         this.name = name;
28     }
29 
30     public int getAge() {
31         return age;
32     }
33 
34     public void setAge(int age) {
35         this.age = age;
36     }
37 
38 }

測試類中代碼如下:

 1 public class ThreadLocalTest {
 2 
 3     private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
 4     private static ThreadLocal<MyThreadScopeData> myThreadLocal = new ThreadLocal<MyThreadScopeData>();
 5 
 6     public static void main(String[] args) {
 7         // 相當於創建了10個線程
 8         for (int i = 0; i < 10; i++) {
 9             new Thread(new Runnable() {
10                 @Override
11                 public void run() {
12                     int data = new Random().nextInt();
13                     System.out.println(Thread.currentThread().getName() + "has put data " + data);
14 //                    MyThreadScopeData myData = new MyThreadScopeData();
15 //                    myData.setName("name" + data);
16 //                    myData.setAge(data);
17 //                    myThreadLocal.set(myData);
18 
19                     MyThreadScopeData.getThreadInstance().setName("name" + data);
20                     MyThreadScopeData.getThreadInstance().setAge(data);
21                     // 存放的是與當前線程相關的數據
22                     x.set(data);
23                     
24 
25                     new A().get();
26                     new B().get();
27                 }
28             }).start();
29         }
30     }
31 
32     static class A {
33         public void get() {
34             int data = x.get();
35             System.out.println("A from " + Thread.currentThread().getName() + "has get data " + data);
36 
37 //            MyThreadScopeData myData = myThreadLocal.get();
38 //            System.out.println("A from " + Thread.currentThread().getName() + "has getMyData " + myData.getName() + ","
39 //                    + myData.getAge());
40             
41             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
42             System.out.println("A from " + Thread.currentThread().getName() + "has getMyData " + myData.getName() + ","
43                     + myData.getAge());
44         }
45     }
46 
47     static class B {
48         public void get() {
49             int data = x.get();
50             System.out.println("B from " + Thread.currentThread().getName() + "has get data " + data);
51             
52 //            MyThreadScopeData myData = myThreadLocal.get();
53 //            System.out.println("B from " + Thread.currentThread().getName() + "has getMyData " + myData.getName() + ","
54 //                    + myData.getAge());
55             
56             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
57             System.out.println("B from " + Thread.currentThread().getName() + "has getMyData " + myData.getName() + ","
58                     + myData.getAge());
59         }
60     }
61 }

總結:這個線程范圍內的數據共享問題,解決的方法中用到了單例模式中的設計思想,但是區別的地方是加了一步將數據存放到ThreadLocal 中,實現數據的共享!

三、多線程訪問共享數據和線程的方式

 也是線程間數據共享的問題,只不過這個是以實戰的角度來探索線程共享間數據的同步問題,主要學的是這種解決實際問題的能力,看看代碼:

 1 public class MultiThreadShareData {
 2 
 3     public static void main(String[] args) {
 4         final ShareData1 data1 = new ShareData1();
 5         
 6         new Thread(new Runnable() {
 7             @Override
 8             public void run() {
 9                 data1.decrement();
10             }
11         }).start();
12         
13         new Thread(new Runnable() {
14             @Override
15             public void run() {
16                 data1.increment();
17             }
18         }).start();
19     }
20 
21     static class ShareData1 /* implements Runnable */ {
22 
23         private int j = 0;
24         private int count = 100;
25 
26         public synchronized void increment() {
27             j++;
28         }
29 
30         public synchronized void decrement() {
31             j--;
32         }
33 
34         /*
35          * @Override public void run() { while (true) { count--; } }
36          */
37     }
38 
39 }

 


免責聲明!

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



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