• 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 }
  • 相关阅读:
    欧几里得算法
    匈牙利算法找二分图最大匹配
    hdu3374 String Problem(最小值表示法 + KMP)
    hdu6704 K-th occurrence(后缀数组+RMQ+主席树)
    洛谷 P3809 【模板】后缀排序
    hdu2222 【AC自动机】Keywords Search
    2019杭电多校十 1011 Make Rounddog Happy(rmq + 分治)
    Separate String(Ac自动机+dp)
    2019杭电多校二 I Love Palindrome String(回文自动机)
    HDU2451 Simple Addition expression(数位dp/找规律)
  • 原文地址:https://www.cnblogs.com/ssh-html/p/10976775.html
Copyright © 2020-2023  润新知