码迷,mamicode.com
首页 > 编程语言 > 详细

多线程之线程范围内的数据共享ThreadLocal

时间:2014-11-08 18:23:05      阅读:245      评论:0      收藏:0      [点我收藏+]

标签:多线程   线程   局部变量   threadlocal   

如果多个线程使用同一个数据,那么如何保证线程范围内的数据共享。

我们可以使用一个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) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 getset 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。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



多线程之线程范围内的数据共享ThreadLocal

标签:多线程   线程   局部变量   threadlocal   

原文地址:http://blog.csdn.net/fengshizty/article/details/40921913

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!