5、ThreadLocals实现线程范围内的共享变量

线程范围内的共享数据
1、未实现线程共享变量

    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);  
            }         
        }  
    }  

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

package cn.itcast.thread;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class TraditionaScopeshareData {
    private static int data=0;
    private static Map<Thread,Integer>  threadData=new HashMap<Thread,Integer>();
    public static void main(String[] args) {
    // TODO Auto-generated method stub
  for(int i=0;i<2;i++){
        new Thread(
                new Runnable() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                         int data=new Random().nextInt();

                        System.out.println(Thread.currentThread().getName()+"has put data:"+data);
                        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()+"has put data:"+data);

        }

    }

    static class B{
        public void get()
        {
            int data =threadData.get(Thread.currentThread());
            System.out.println("B from"+Thread.currentThread().getName()+"has put data:"+data);

        }
    }

}

实现结果

Thread-0has put data:-498492583
Thread-1has put data:381688615
A fromThread-0has put data:-498492583
B fromThread-0has put data:-498492583
A fromThread-1has put data:381688615
B fromThread-1has put data:381688615

ThreadLocals实现方式

package cn.itcast.thread;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class ThreadLocalTest {
    private static ThreadLocal<Integer> x = new ThreadLocal<Integer>(); 
    public static void main(String[] args) {
    // TODO Auto-generated method stub
  for(int i=0;i<2;i++){
        new Thread(
                new Runnable() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                         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()+"has put data:"+data);

        }

    }

    static class B{
        public void get()
        {
             int data = x.get();
             System.out.println("B from"+Thread.currentThread().getName()+"has put data:"+data);

        }
    }

}

结果

Thread-0has put data:-145623389
A fromThread-0has put data:-145623389
B fromThread-0has put data:-145623389
Thread-1has put data:433511551
A fromThread-1has put data:433511551
B fromThread-1has put data:433511551

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

package cn.itcast.thread;

    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;  
        }  
    }  

结果

Thread-1 has put data :-1622741359
Thread-0 has put data :-648762367
A from Thread-1 getMyData: name-1622741359,-1622741359
A from Thread-0 getMyData: name-648762367,-648762367
B from Thread-0 getMyData: name-648762367,-648762367
B from Thread-1 getMyData: name-1622741359,-1622741359

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

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值