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掉

  

时间: 2024-12-25 18:30:18

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

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

线程池 线程池的思想  线程池的概念与Executors类的应用 > 创建固定大小的线程池 > 创建缓存线程池 > 创建单一线程池(如何实现线程死掉后重新启动?) 关闭线程池 > shutdown 与 shutdownNow的比较 用线程池启动定时器 > 调用ScheduleExecutorService 的 schedule 方法,返回的ScheduleFuture对象可以取消任务. > 支持间隔重复任务的定时方式,不直接支持决定定时的方法,需要转换成相对时间方式.

Java多线程与并发库高级应用之线程数据交换Exchanger

JDK1.5提供了Exchanger用于两个线程的数据交换.两个线程先后到达交换点,先到达的线程会等待后到达的线程,然后两个线程互相交换数据,交换后双方持对方的数据. Exchanger只提供了一个构造器: Exchanger():创建一个新的Exchanger. Exchanger中也只有两个方法: V exchange(V x): 等待另一个线程到达此交换点(除非当前线程被中断),然后将给定的对象传送给该线程,并接收该线程的对象. V exchange(V x, long timeout,

Java多线程与并发库高级应用之公共屏障点CyclicBarrier

一个小队去登山,每位队员登山的速度不同.山上有几个集合点,在每一集合点处,先到达的队员只有等后面的队员全部到达集合点后才能继续向下一个集合点出发. JDK1.5提供的CyclicBarrier模拟了这种情况.每一个线程相当于一个登山队员,CyclicBarrier相当于山上的集合点.只有等所有线程都执行到了CyclicBarrier后才可以继续向下执行. CyclicBarrier允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程

Java多线程与并发库高级应用之信号量Semaphore

JDK1.5提供了一个计数信号量Semaphore类.Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目,并提供了同步机制. Semaphore提供了两个构造器来创建对象: 1)Semaphore(int permits):创建具有给定的许可数和非公平的公平设置的Semaphore. 2)Semaphore(int permits, boolean fair):创建具有给定的许可数和给定的公平设置的Semaphore.如果此信号量保证在争用时按先进先出的顺序授予许可,则为

Java多线程与并发库高级应用之阻塞队列BlockingQueue

JDK1.5提供了阻塞队列接口BlockingQueue,它是一个有界阻塞队列.BlockingQueue实现是线程安全的,可以安全地与多个生产者和多个使用者一起使用. 使用时用其实现类 ArrayBlockingQueue,它一个由数组支持的有界阻塞队列.此队列按 FIFO(先进先出)原则对元素进行排序.队列的头部 是在队列中存在时间最长的元素.队列的尾部是在队列中存在时间最短的元素.新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素. 这是一个典型的"有界缓存区",固定

Java多线程与并发库高级应用之倒计时计数器

CountDownLatch 类是一个倒计时计数器,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待.用给定的计数初始化 CountDownLatch.由于调用了countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞.之后,会释放所有等待的线程,await 的所有后续调用都将立即返回. CountDownLatch 是一个通用同步工具,它有很多用途.将计数1初始化的 CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 c

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

java5 中的线程并发库 主要在java.util.concurrent包中 还有 java.util.concurrent.atomic子包和java.util.concurrent.lock子包

(黑马Java多线程与并发库高级应用)04 传统线程同步通信技术

子线程10次,然后主线程100次,然后子线程10次,然后主线程100次.循环50次 package cn.itcast.heima2; public class TraditionalThreadComunication { public static void main(String[] args) { // TODO Auto-generated method stub Business business = new TraditionalThreadComunication().new B

Java多线程与并发库高级应用-工具类介绍

java.util.concurrent.Lock Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. lock替代synchronized class Outputer { Lock lock = new ReentrantLock(); public void output(String name) { int len = name.length(); loc