JAVA 并发编程-线程范围内共享变量(五)
发布日期:2022-01-11 03:09:48 浏览次数:6 分类:技术文章

本文共 6363 字,大约阅读时间需要 21 分钟。

线程范围内共享变量要实现的效果为:

 

多个对象间共享同一线程内的变量

未实现线程共享变量的demo

[java]
  1. package cn.itcast.heima2;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5. import java.util.Random;  
  6.   
  7. public class ThreadScopeShareData {  
  8.   
  9.     private static int data = 0;  
  10. //  private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();  
  11.       
  12.     public static void main(String[] args) {  
  13.         //共启动2个线程  
  14.         for(int i=0;i<2;i++){  
  15.             //启动一个线程  
  16.             new Thread(new Runnable(){  
  17.                 @Override  
  18.                 public void run() {  
  19.                     data = new Random().nextInt();  
  20.                     System.out.println(Thread.currentThread().getName()   
  21.                             + " has put data :" + data);  
  22.                     //以当前线程为key值放入到map中,当取值时根据各自的线程取各自的数据  
  23. //                  threadData.put(Thread.currentThread(), data);  
  24.                     new A().get();  
  25.                     new B().get();  
  26.                 }  
  27.             }).start();  
  28.         }  
  29.     }  
  30.       
  31.     static class A{  
  32.         public void get(){  
  33. //          int data = threadData.get(Thread.currentThread());  
  34.             System.out.println("A from " + Thread.currentThread().getName()   
  35.                     + " get data :" + data);  
  36.         }  
  37.     }  
  38.       
  39.     static class B{  
  40.         public void get(){  
  41. //          int data = threadData.get(Thread.currentThread());            
  42.             System.out.println("B from " + Thread.currentThread().getName()   
  43.                     + " get data :" + data);  
  44.         }         
  45.     }  
  46. }  

运行结果:

通过打印出的结果可以看出,当Thread-0获取了一个随机数,修改了data的值,正在睡眠的时候,Thread-1又获取了一个随机数,同样修改了data的值,然后Thread-1调用了静态内部类ABget方法,实际上此时的data已经是Thread-1拿到的随机数了。

当然,我们可以通过增加synchronized加锁来控制线程的运行。让Thread-0运行完方法之前,Thread-1不能修改data的值。

此外,还可以使用另外几种方法来获取线程运行时变量赋予的真正值。

线程范围内共享变量实现方式: 

 

Map实现方式:

[java]
  1. package cn.itcast.heima2;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5. import java.util.Random;  
  6.   
  7. public class ThreadScopeShareData {  
  8.   
  9.       
  10.     private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();  
  11.       
  12.     public static void main(String[] args) {  
  13.         //共启动2个线程  
  14.         for(int i=0;i<2;i++){  
  15.             //启动一个线程  
  16.             new Thread(new Runnable(){  
  17.                 @Override  
  18.                 public void run() {  
  19.                     int data = new Random().nextInt();  
  20.                     System.out.println(Thread.currentThread().getName()   
  21.                             + " has put data :" + data);  
  22.                     //以当前线程为key值放入到map中,当取值时根据各自的线程取各自的数据  
  23.                     threadData.put(Thread.currentThread(), data);  
  24.                     new A().get();  
  25.                     new B().get();  
  26.                 }  
  27.             }).start();  
  28.         }  
  29.     }  
  30.       
  31.     static class A{  
  32.         public void get(){  
  33.             int data = threadData.get(Thread.currentThread());  
  34.             System.out.println("A from " + Thread.currentThread().getName()   
  35.                     + " get data :" + data);  
  36.         }  
  37.     }  
  38.       
  39.     static class B{  
  40.         public void get(){  
  41.             int data = threadData.get(Thread.currentThread());            
  42.             System.out.println("B from " + Thread.currentThread().getName()   
  43.                     + " get data :" + data);  
  44.         }         
  45.     }  
  46. }  

运行结果:

 

ThreadLocal方式:

[java]
  1. package cn.itcast.heima2;  
  2.   
  3. import java.util.Random;  
  4.   
  5. public class ThreadLocalTest {  
  6.   
  7.     private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();  
  8.     public static void main(String[] args) {  
  9.         for(int i=0;i<2;i++){  
  10.             new Thread(new Runnable(){  
  11.                 @Override  
  12.                 public void run() {  
  13.                     int data = new Random().nextInt();  
  14.                     System.out.println(Thread.currentThread().getName()   
  15.                             + " has put data :" + data);  
  16.                     x.set(data);  
  17.                     new A().get();  
  18.                     new B().get();  
  19.                 }                             
  20.             }).start();  
  21.         }  
  22.     }  
  23.       
  24.     static class A{  
  25.         public void get(){  
  26.             int data = x.get();  
  27.             System.out.println("A from " + Thread.currentThread().getName()   
  28.                     + " get data :" + data);  
  29.         }  
  30.     }  
  31.       
  32.     static class B{  
  33.         public void get(){  
  34.             int data = x.get();           
  35.             System.out.println("B from " + Thread.currentThread().getName()   
  36.                     + " get data :" + data);                      
  37.         }         
  38.     }  
  39. }  

存在的问题:一个ThreadLocal代表一个变量,故其中只能放一个数据,如果你有两个变量要线程范围内共享,则要定义两个ThreadLocal。如下为解决方案:

 

扩展方式-单例方式处理对象:

[java]
  1. package cn.itcast.heima2;  
  2.   
  3. import java.util.Random;  
  4.   
  5. public class ThreadLocalTest {  
  6.   
  7. //  方式一  
  8. //  private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();  
  9.       
  10.     private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();  
  11.     public static void main(String[] args) {  
  12.         for(int i=0;i<2;i++){  
  13.             new Thread(new Runnable(){  
  14.                 @Override  
  15.                 public void run() {  
  16.                     int data = new Random().nextInt();  
  17.                     System.out.println(Thread.currentThread().getName()   
  18.                             + " has put data :" + data);  
  19. //                  方式一 ThreadLocal  
  20. //                  x.set(data);  
  21. //                  方式二 new对象方式,将多个属性放到对象中  
  22. //                  MyThreadScopeData myData = new MyThreadScopeData();  
  23. //                  myData.setName("name" + data);  
  24. //                  myData.setAge(data);  
  25. //                  myThreadScopeData.set(myData);  
  26. //                  方式三 使用单例模式  
  27.                     MyThreadScopeData.getThreadInstance().setName("name" + data);  
  28.                     MyThreadScopeData.getThreadInstance().setAge(data);  
  29.                       
  30.                     new A().get();  
  31.                     new B().get();  
  32.                 }                             
  33.             }).start();  
  34.         }  
  35.     }  
  36.       
  37.     static class A{  
  38.         public void get(){  
  39. //          方式一 ThreadLocal  
  40. //          int data = x.get();  
  41. //          System.out.println("A from " + Thread.currentThread().getName()   
  42. //                  + " get data :" + data);  
  43. //          方式二 new对象方式,将多个属性放到对象中  
  44. //          MyThreadScopeData myData = myThreadScopeData.get();;  
  45. //          System.out.println("A from " + Thread.currentThread().getName()   
  46. //                  + " getMyData: " + myData.getName() + "," +  
  47. //                  myData.getAge());  
  48. //          方式三 使用单例模式  
  49.             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();  
  50.             System.out.println("A from " + Thread.currentThread().getName()   
  51.                     + " getMyData: " + myData.getName() + "," +  
  52.                     myData.getAge());  
  53.         }  
  54.     }  
  55.       
  56.     static class B{  
  57.         public void get(){  
  58. //          int data = x.get();           
  59. //          System.out.println("B from " + Thread.currentThread().getName()   
  60. //                  + " get data :" + data);  
  61. //          MyThreadScopeData myData = myThreadScopeData.get();;  
  62. //          System.out.println("B from " + Thread.currentThread().getName()   
  63. //                  + " getMyData: " + myData.getName() + "," +  
  64. //                  myData.getAge());  
  65.             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();  
  66.             System.out.println("B from " + Thread.currentThread().getName()   
  67.                     + " getMyData: " + myData.getName() + "," +  
  68.                     myData.getAge());             
  69.         }         
  70.     }  
  71. }  
  72.   
  73. class MyThreadScopeData{  
  74.       
  75.     private MyThreadScopeData(){}  
  76.       
  77.     private static MyThreadScopeData instance = null;//new MyThreadScopeData();  
  78.       
  79.     private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();  
  80.       
  81.     public static /*synchronized*/ MyThreadScopeData getThreadInstance(){  
  82.         MyThreadScopeData instance = map.get();  
  83.         if(instance == null){  
  84.             instance = new MyThreadScopeData();  
  85.             map.set(instance);  
  86.         }  
  87.         return instance;  
  88.     }  
  89.       
  90.       
  91.     private String name;  
  92.     private int age;  
  93.     public String getName() {  
  94.         return name;  
  95.     }  
  96.     public void setName(String name) {  
  97.         this.name = name;  
  98.     }  
  99.     public int getAge() {  
  100.         return age;  
  101.     }  
  102.     public void setAge(int age) {  
  103.         this.age = age;  
  104.     }  
  105. }  

总结:

 

    synchronized和使用ThreadLocal均可以解决以上的问题,只是这是两种不同的方式,synchronized是依赖锁的机制一个执行完后另一个再执行。ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。

    概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

    当然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多个线程进行同步了。

    ThreadLocal的应用:

    在业务逻辑层需要调用多个Dao层的方法,我们要保证事务(jdbc事务)就要确保他们使用的是同一个连接.那么如何确保使用同一个数据库连接呢?

转载地址:https://yuki-ho.blog.csdn.net/article/details/52217522 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:野狗(wilddog)帮助类
下一篇:JAVA 并发编程-传统线程同步通信技术(四)

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月21日 16时06分17秒