问题:实现线程范围内的数据共享,即每个线程只能访问它自己的数据,不能访问其他线程的数据。具体逻辑如下图所示:

线程数据共享JAVA java线程共享部分_多线程

1.方法一:使用Map<线程Thread,数据类型DataType>
使用Map<线程Thread,数据类型DataType>,其中key为Thread,即线程;value为DataType,即要线程范围内共享的数据的数据类型。这样就可以通过线程来获取其相应的数据。案例如下:

package com.lesson5;

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

/*
 * 问题:实现线程范围内的数据共享 
 */
public class ThreadScopeShareData {
    //ThreadLocal就相当于Map<Thread,Integer>
    private static Map<Thread,Integer> threadData=new HashMap<Thread,Integer>();

    public static void main(String[] args){
        for(int i=0;i<2;i++){
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    int data = new Random().nextInt();
                    threadData.put(Thread.currentThread(), data);
                    System.out.println(Thread.currentThread().getName()+ " put data: " + threadData.get(Thread.currentThread()));
                    new A().get();
                    new B().get();
                }
            };
            Thread t = new Thread(r);
            t.start();
        }

    }

    static class A{
        public void get(){
            System.out.println("A from "+Thread.currentThread().getName()+" get data:"+threadData.get(Thread.currentThread()));
        }
    }

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

运行结果如下:

线程数据共享JAVA java线程共享部分_数据共享_02


2.方法二:使用ThreadLocal

       ThreadLocal的作用和目的:用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。每个线程调用全局ThreadLocal对象的set方法,就相当于在其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值。在线程结束时可以调用ThreadLocal.clear()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。案例如下:

package com.lesson5;

import java.util.Random;

/*
 * 问题:使用ThreadLocal实现线程范围内的数据共享
 */
public class ThreadLocalShareData {
    //定义一个全局的ThreadLocal变量
    static ThreadLocal<Integer> x=new ThreadLocal<Integer>();

    public static void main(String[] args){
        //启动多个线程向ThreadLocal变量中存储一个随机值
        for(int i=0;i<2;i++){
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    int data = new Random().nextInt();
                    x.set(data);
                    System.out.println(Thread.currentThread().getName()+ " put data: " + data);
                    //各个线程调用其他多个类的方法读取ThreadLocal变量中的值,可以看到多个类在同一个线程中共享同一份数据
                    new A().get();
                    new B().get();
                }
            };
            Thread t = new Thread(r);
            t.start();
        }
    }

    static class A{
        public void get(){
            System.out.println("A from "+Thread.currentThread().getName()+" get data:"+x.get());
        }
    }

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

线程数据共享JAVA java线程共享部分_数据共享_03

3.封装ThreadLocal,封装线程共享变量

package com.lesson5;

import java.util.Random;

/*
 * 问题:一个ThreadLocal的value代表一个变量,故其中只能存放一个数据,当有两个变量都要线程范围内共享呢?一个简单
 *     的方法是定义两个ThreadLocal对象,但如果有100个变量要线程共享又该怎么办呢?
 * 改进:实现对ThreadLocal变量的封装,让外界不直接操作ThreadLocal变量。对对象类型的数据的封装,比较常见,
 *     即,让某个类针对不同线程分别创建不同的实例对象。上述问题的解决方法是,先定义一个对象来疯转这100个变量,然后再在
 *     ThreadLocal中存储这一对象。
 * 
 */
public class ThreadLocalShareData2 {

    public static void main(String[] args){
        for(int i=0;i<2;i++){
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    int data = new Random().nextInt();
                    MyThreadScopeData myThreadScopeData=MyThreadScopeData.getThreadInstance();
                    myThreadScopeData.setName("itsname"+data);
                    myThreadScopeData.setAge(data);
                    System.out.println(Thread.currentThread().getName()+ " put data: " + data);
                    new A().get();
                    new B().get();
                }
            };
            Thread t = new Thread(r);
            t.start();
        }
    }

    static class A{
        public void get(){
            MyThreadScopeData myThreadScopeData=MyThreadScopeData.getThreadInstance();
            System.out.println("A from "+Thread.currentThread().getName()+" get data: name="+myThreadScopeData.getName()+" age="+myThreadScopeData.getAge());
        }
    }

    static class B{
        public void get(){
            MyThreadScopeData myThreadScopeData=MyThreadScopeData.getThreadInstance();
            System.out.println("B from "+Thread.currentThread().getName()+" get data: name="+myThreadScopeData.getName()+" age="+myThreadScopeData.getAge());
        }
    }
}

class MyThreadScopeData{
    //封装的变量,可以封装任意多个
    private String name;
    private int age;

    //饿汉式单例
    private static ThreadLocal<MyThreadScopeData> threadLocalMap=new ThreadLocal<MyThreadScopeData>();

    //封装ThreadLocal对象,向外提供获取相应线程共享数据的接口
    public static MyThreadScopeData getThreadInstance(){
        MyThreadScopeData instance=threadLocalMap.get();
        if(instance==null){
            instance=new MyThreadScopeData();
            threadLocalMap.set(instance);
        }
        return instance;
    }


    //懒汉式单例
    /*private static ThreadLocal<MyThreadScopeData> threadLocalMap=null;

    //封装ThreadLocal对象,向外提供获取相应线程共享数据的接口
    public static MyThreadScopeData getThreadInstance(){
        synchronized(MyThreadScopeData.class){
            if(threadLocalMap==null){
                System.out.println("执行一次......");
                threadLocalMap=new ThreadLocal<MyThreadScopeData>();
            }
        }

        //instance不是所有线程共享的数据,因此不需要同步
        MyThreadScopeData instance=threadLocalMap.get();
        if(instance==null){
            instance=new MyThreadScopeData();
            threadLocalMap.set(instance);
        }
        return instance;
    }*/

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

运行结果如下:

线程数据共享JAVA java线程共享部分_java_04