通过ThreadLoad实现线程范围内的共享变量

来源:互联网 发布:mysql主从同步原理 编辑:程序博客网 时间:2024/06/03 13:50

线程共享变量可能出现的问题


使用ThreadLocal来避免共享变量的并发问题


实例代码

package cn.iktz.thread.demo;import java.util.Random;public class ThreadLocalTest2 {public static void main(String[] args) {for (int i = 0; i < 2; i++) {new Thread(new ThreadLocalTestSetData()).start();}}}class Object1 {public void get(ThreadLocal<Integer> x) {System.out.println("A from " + Thread.currentThread().getName() + " get data :" + x.get());}}class ThreadLocalTestSetData implements Runnable {private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();@Overridepublic void run() {int data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + " has put data :" + data);threadLocal.set(data);// threadLocl用来存储数据,存储的数据与当前线程有关的而非全局的MyThreadScopeData.getThreadInstance().setName("name" + data);MyThreadScopeData.getThreadInstance().setAge(data);new Object1().get(threadLocal);}}

对ThreadLocal进行封装

package cn.iktz.thread.demo;import java.util.Random;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ThreadLocalTest3 {public static void main(String[] args) {for (int i = 0; i < 2; i++) {new Thread(new Runnable() {@Overridepublic void run() {int data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + " has put data :" + data);MyThreadScopeData.getThreadInstance().setName("name" + data);MyThreadScopeData.getThreadInstance().setAge(data);new A().get();}}).start();}}static class A {public void get() {MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();System.out.println("A from " + Thread.currentThread().getName() + " getMyData: " + myData.getName() + ","+ myData.getAge());}}static class MyThreadScopeData {private MyThreadScopeData() {}static Lock lock = new ReentrantLock();public static MyThreadScopeData getThreadInstance() {lock.lock();try {MyThreadScopeData instance = map.get();if (instance == null) {instance = new MyThreadScopeData();/** 这里可能会出现并发问题,所以要加锁。  这里如果a线程创建了对象,并赋值,此时instance指向0X6666, 然后b来了get为null,也会创建一个对象并赋值,此时instance指向0x7777,0x6666被覆盖 b线程放入了0x7777的对象,此时切换到a线程,a也会放入0x7777的对象,则出现并发问题 */map.set(instance);}return instance;} finally{lock.unlock();}}private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();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;}}}


线程退出时清空该线程ThreadLocal的数据,看api可以知道,gc线程,会回收只被ThreadLocal引用的对象
0 0