如果多个线程使用同一个数据,那么如何保证线程范围内的数据共享。
我们可以使用一个map来存储当前线程,以及其数据如下:
package andy.thread.traditional.test; import java.util.HashMap; import java.util.Map; import java.util.Random; /** * @author Zhang,Tianyou * @version 2014年11月8日 下午2:12:44 */ // 线程范围内的共享数据 public class ThreadScopeSharedData { private static int data = 0; //ThreadLocal 提供了线程范围内的数据共享 只能存贮一个数据 private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>(); //private static ThreadLocal<Integer> x = new ThreadLocal<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() + " has put data :" + data); threadData.put(Thread.currentThread(), data); //x.set(data); new A().get(); new B().get(); } }).start(); } } static class A { public void get() { int data = threadData.get(Thread.currentThread()); //int data = x.get(); System.out.println("A from " + Thread.currentThread().getName() + " get data :" + data); } } static class B { public void get() { int data = threadData.get(Thread.currentThread()); //int data = x.get(); System.out.println("B from " + Thread.currentThread().getName() + " get data :" + data); } } }
运行效果如下:
Thread-1 has put data :-591164568 Thread-0 has put data :2032497041 A from Thread-0 get data :2032497041 A from Thread-1 get data :-591164568 B from Thread-0 get data :2032497041 B from Thread-1 get data :-591164568
但JDK也为我们提供了另一种实现方式:ThreadLocal类,它能够实现各自线程局部变量,并且独立于变量的初始化副本。
-
public class ThreadLocal<T>
- extends Object
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
例如,以下类生成对每个线程唯一的局部标识符。线程 ID 是在第一次调用 UniqueThreadIdGenerator.getCurrentThreadId() 时分配的,在后续调用中不会更改。
import java.util.concurrent.atomic.AtomicInteger; public class UniqueThreadIdGenerator { private static final AtomicInteger uniqueId = new AtomicInteger(0); private static final ThreadLocal < Integer > uniqueNum = new ThreadLocal < Integer > () { @Override protected Integer initialValue() { return uniqueId.getAndIncrement(); } }; public static int getCurrentThreadId() { return uniqueId.get(); } } // UniqueThreadIdGenerator
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
上面代码的更优雅的实现如下:
package andy.thread.traditional.test; import java.util.Random; /** * @author Zhang,Tianyou * @version 2014年11月8日 下午2:26:24 */ public class ThreadLocalTest { private static int data = 0; // 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() + " has put data :" + data); MyThreadScopeData.getThreadScopeInstance().setName( "name = " + data); MyThreadScopeData.getThreadScopeInstance().setAge(data); new A().get(); new B().get(); } }).start(); } } static class A { public void get() { MyThreadScopeData myThreadScopeData = MyThreadScopeData .getThreadScopeInstance(); System.out.println("A from " + Thread.currentThread().getName() + " Name :" + myThreadScopeData.getName() + "age = " + myThreadScopeData.getAge()); } } static class B { public void get() { MyThreadScopeData myThreadScopeData = MyThreadScopeData .getThreadScopeInstance(); System.out.println("B from " + Thread.currentThread().getName() + " Name :" + myThreadScopeData.getName() + "age = " + myThreadScopeData.getAge()); } } } class MyThreadScopeData { private MyThreadScopeData() { } private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>(); // 此处不需要synchronized 应该每个线程操作各自的数据 public static MyThreadScopeData getThreadScopeInstance() { // 返回此线程局部变量的当前线程副本中的值。 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 :1322483490 A from Thread-1 Name :name = 1322483490age = 1322483490 B from Thread-1 Name :name = 1322483490age = 1322483490 Thread-0 has put data :1149801771 A from Thread-0 Name :name = 1149801771age = 1149801771 B from Thread-0 Name :name = 1149801771age = 1149801771
时间: 2024-10-25 00:12:41