JAVA 并发编程-线程范围内共享变量(五)

    xiaoxiao2026-02-26  6

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

     

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

    未实现线程共享变量的demo

    [java] view plain copy print ? package cn.itcast.heima2;    import java.util.HashMap;  import java.util.Map;  import java.util.Random;    public class ThreadScopeShareData {        private static int data = 0;  //  private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();            public static void main(String[] args) {          //共启动2个线程          for(int i=0;i<2;i++){              //启动一个线程              new Thread(new Runnable(){                  @Override                  public void run() {                      data = new Random().nextInt();                      System.out.println(Thread.currentThread().getName()                               + " has put data :" + data);                      //以当前线程为key值放入到map中,当取值时根据各自的线程取各自的数据  //                  threadData.put(Thread.currentThread(), data);                      new A().get();                      new B().get();                  }              }).start();          }      }            static class A{          public void get(){  //          int data = threadData.get(Thread.currentThread());              System.out.println("A from " + Thread.currentThread().getName()                       + " get data :" + data);          }      }            static class B{          public void get(){  //          int data = threadData.get(Thread.currentThread());                        System.out.println("B from " + Thread.currentThread().getName()                       + " get data :" + data);          }             }  }  

    运行结果:

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

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

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

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

     

    Map实现方式:

    [java] view plain copy print ? package cn.itcast.heima2;    import java.util.HashMap;  import java.util.Map;  import java.util.Random;    public class ThreadScopeShareData {              private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();            public static void main(String[] args) {          //共启动2个线程          for(int i=0;i<2;i++){              //启动一个线程              new Thread(new Runnable(){                  @Override                  public void run() {                      int data = new Random().nextInt();                      System.out.println(Thread.currentThread().getName()                               + " has put data :" + data);                      //以当前线程为key值放入到map中,当取值时根据各自的线程取各自的数据                      threadData.put(Thread.currentThread(), data);                      new A().get();                      new B().get();                  }              }).start();          }      }            static class A{          public void get(){              int data = threadData.get(Thread.currentThread());              System.out.println("A from " + Thread.currentThread().getName()                       + " get data :" + data);          }      }            static class B{          public void get(){              int data = threadData.get(Thread.currentThread());                        System.out.println("B from " + Thread.currentThread().getName()                       + " get data :" + data);          }             }  }  

    运行结果:

     

    ThreadLocal方式:

    [java] view plain copy print ? package cn.itcast.heima2;    import java.util.Random;    public class ThreadLocalTest {        private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();      public static void main(String[] args) {          for(int i=0;i<2;i++){              new Thread(new Runnable(){                  @Override                  public void run() {                      int data = new Random().nextInt();                      System.out.println(Thread.currentThread().getName()                               + " has put data :" + data);                      x.set(data);                      new A().get();                      new B().get();                  }                                         }).start();          }      }            static class A{          public void get(){              int data = x.get();              System.out.println("A from " + Thread.currentThread().getName()                       + " get data :" + data);          }      }            static class B{          public void get(){              int data = x.get();                       System.out.println("B from " + Thread.currentThread().getName()                       + " get data :" + data);                              }             }  }  

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

     

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

    [java] view plain copy print ? package cn.itcast.heima2;    import java.util.Random;    public class ThreadLocalTest {    //  方式一  //  private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();            private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();      public static void main(String[] args) {          for(int i=0;i<2;i++){              new Thread(new Runnable(){                  @Override                  public void run() {                      int data = new Random().nextInt();                      System.out.println(Thread.currentThread().getName()                               + " has put data :" + data);  //                  方式一 ThreadLocal  //                  x.set(data);  //                  方式二 new对象方式,将多个属性放到对象中  //                  MyThreadScopeData myData = new MyThreadScopeData();  //                  myData.setName("name" + data);  //                  myData.setAge(data);  //                  myThreadScopeData.set(myData);  //                  方式三 使用单例模式                      MyThreadScopeData.getThreadInstance().setName("name" + data);                      MyThreadScopeData.getThreadInstance().setAge(data);                                            new A().get();                      new B().get();                  }                                         }).start();          }      }            static class A{          public void get(){  //          方式一 ThreadLocal  //          int data = x.get();  //          System.out.println("A from " + Thread.currentThread().getName()   //                  + " get data :" + data);  //          方式二 new对象方式,将多个属性放到对象中  //          MyThreadScopeData myData = myThreadScopeData.get();;  //          System.out.println("A from " + Thread.currentThread().getName()   //                  + " getMyData: " + myData.getName() + "," +  //                  myData.getAge());  //          方式三 使用单例模式              MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();              System.out.println("A from " + Thread.currentThread().getName()                       + " getMyData: " + myData.getName() + "," +                      myData.getAge());          }      }            static class B{          public void get(){  //          int data = x.get();           //          System.out.println("B from " + Thread.currentThread().getName()   //                  + " get data :" + data);  //          MyThreadScopeData myData = myThreadScopeData.get();;  //          System.out.println("B from " + Thread.currentThread().getName()   //                  + " getMyData: " + myData.getName() + "," +  //                  myData.getAge());              MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();              System.out.println("B from " + Thread.currentThread().getName()                       + " getMyData: " + myData.getName() + "," +                      myData.getAge());                     }             }  }    class MyThreadScopeData{            private MyThreadScopeData(){}            private static MyThreadScopeData instance = null;//new MyThreadScopeData();            private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();            public static /*synchronized*/ MyThreadScopeData getThreadInstance(){          MyThreadScopeData instance = map.get();          if(instance == null){              instance = new MyThreadScopeData();              map.set(instance);          }          return instance;      }                  private String name;      private int age;      public String getName() {          return name;      }      public void setName(String name) {          this.name = name;      }      public int getAge() {          return age;      }      public void setAge(int age) {          this.age = age;      }  }  

    总结:

     

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

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

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

        ThreadLocal的应用:

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

    转载请注明原文地址: https://ju.6miu.com/read-1307387.html
    最新回复(0)