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 }
原文地址:https://www.cnblogs.com/ssh-html/p/10976775.html