Java线程与并发库高级应用-线程范围内共享数据ThreadLocal类

Posted wq3435

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java线程与并发库高级应用-线程范围内共享数据ThreadLocal类相关的知识,希望对你有一定的参考价值。

1.线程范围内共享变量

  

1.1 前奏:

使用一个Map来实现线程范围内共享变量

  

public class ThreadScopeShareData {

    static Map<Thread, Integer> dataMap = new HashMap<Thread, 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()
                            + " put data " + data);
                    dataMap.put(Thread.currentThread(), data);
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }

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

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

}

 

  

1.2 ThreadLocal类实际上就是一种map

/**
 * ThreadLocal 类 这里ThreadLocal存放一个变量,如果有多个变量, 可以先将多个变量封装为一个对象
 * 
 * @author Administrator
 * 
 */
public class ThreadLocalTest {
    static ThreadLocal<Integer> x = new ThreadLocal<>(); //

    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()
                            + " put data " + data);
                    x.set(data);
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }

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

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

}

 2.线程范围内共享多个变量,可以将多个变量封装为一个对象

/**
 * ThreadLocal 类 这里ThreadLocal存放一个变量,如果有多个变量, 可以先将多个变量封装为一个对象
 * 
 * @author Administrator
 * 
 */
public class ThreadLocalTest {
    static ThreadLocal<Integer> x = new ThreadLocal<>(); //

    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()
                            + " put data " + data);
                    x.set(data);
                    MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();//获取与线程绑定的对象
                    myData.setName("name"+data);
                    myData.setAge(data);
                    System.out.println(Thread.currentThread().getName()
                            + " put Object " + "name: "+myData.getName()+","+" age: "+myData.getAge());
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }

    static class A {
        public void get() {
            System.out.println(Thread.currentThread().getName() + " get data "
                    + x.get());
            MyThreadScopeData instance = MyThreadScopeData.getThreadInstance(); //直接获取与该线程相关的对象
            System.out.println(Thread.currentThread().getName() + " get Object "
                    + "name: "+instance.getName()+","+" age: "+instance.getAge());
        }
    }

    static class B {
        public void get() {
            System.out.println(Thread.currentThread().getName() + "get data "
                    + x.get());
            MyThreadScopeData instance = MyThreadScopeData.getThreadInstance(); //直接获取与该线程相关的对象
            System.out.println(Thread.currentThread().getName() + " get Object "
                    + "name: "+instance.getName()+","+" age: "+instance.getAge());
        }
    }

}

// 单例
class MyThreadScopeData {  //类的实例是与线程相关的,那么类的设计就交由类自身完成,只要调用自然就是与线程有关的 
    private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<>();

    private MyThreadScopeData() {

    }

    public static MyThreadScopeData getThreadInstance() { // 线程间是相互独立的,这里不需要考虑同步
        MyThreadScopeData instance = map.get();
        if (instance == null) {
            instance = new MyThreadScopeData();
            map.set(instance);
        }
        return instance;
    }

    private String name;
    private Integer age;

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name
     *            the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the age
     */
    public Integer getAge() {
        return age;
    }

    /**
     * @param age
     *            the age to set
     */
    public void setAge(Integer age) {
        this.age = age;
    }

}

 

打印结果

Thread-1 put data -723086824
Thread-0 put data 772514756
Thread-1 put Object name: name-723086824, age: -723086824
Thread-0 put Object name: name772514756, age: 772514756
Thread-0 get data 772514756
Thread-1 get data -723086824
Thread-0 get Object name: name772514756, age: 772514756
Thread-1 get Object name: name-723086824, age: -723086824
Thread-0get data 772514756
Thread-1get data -723086824
Thread-0 get Object name: name772514756, age: 772514756
Thread-1 get Object name: name-723086824, age: -723086824

类的实例是与线程相关的,那么类的设计就交由类自身完成,只要调用自然就是与线程有关的  strust2的主要思想就是这么设计的

参看JAVA API

ThreadLocal有一个 remove()方法

可以移除与该线程相关的变量

remove()
Removes the current thread‘s value for this thread-local variable.

 

补充:

  虚拟机的对应类 Runtime ,中有一个方法 addShutdownHook(Thread hook)

  addShutdownHook(Thread hook)
  Registers a new virtual-machine shutdown hook.

  例如可以写一个发送邮件的线程Thread,当虚拟机挂掉之前会调用传入的Thread,发送一封邮件。

线程中是不是也应该有这种机制,当一个线程挂掉之前可以执行一个之前注册好的事件,或者有一个监听器在监听线程的状态,从而进行回调

在获取到线程挂掉的通知,就可以把该线程相关的变量全部remove获取clear掉

  

 














以上是关于Java线程与并发库高级应用-线程范围内共享数据ThreadLocal类的主要内容,如果未能解决你的问题,请参考以下文章

Java 多线程与并发(案例 + 应用)

Java 多线程与并发(案例 + 应用)

java并发线程范围内共享数据

(黑马Java多线程与并发库高级应用)02 传统定时器技术回顾

多线程并发库

Java多线程与并发库高级应用-java5线程并发库