首页 > 代码库 > 多线程06_张孝祥-ThreadLocal类及应用技巧

多线程06_张孝祥-ThreadLocal类及应用技巧

使用ThreadLocal类实现线程范围内的共享数据:

确保每个线程都有自己私有的变量和取到自己的变量。下面用ThreadLocal类实现,替代上节课中的map用法

代码:

package org.yla.thread;

import java.util.Random;

/**
 * 使用ThreadLocal类实现线程范围内的私有数据
 * 替代上节课map的作用
 * @author huo_chai_gun
 * 2014年12月18日下午3:25:35
 */
public class ThreadLocalTest {

	private static ThreadLocal<Integer> threadLocal = 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(100);
					System.out.println(Thread.currentThread().getName()+" has put data: "+data);
					//往local里面设置值
					threadLocal.set(data);
					new A().get();
					new B().get();
				}
			}).start();
		}
	}
	
	static class A{
		public void get(){
			int data =threadLocal.get();
			System.out.println("A from "+Thread.currentThread().getName()+" has get data: "+data);
		}
	}
	
	
	static class B{
		public void get(){
			int data =threadLocal.get();
			System.out.println("B from "+Thread.currentThread().getName()+" has get data: "+data);
		}
	}
}






运行结果:

Thread-0 has put data: 48
Thread-1 has put data: 95
A from Thread-1 has get data: 95
A from Thread-0 has get data: 48
B from Thread-0 has get data: 48
B from Thread-1 has get data: 95

假设我们有多个线程需要范围内的共享数据,那么我们的代码就得改成下面的形式了:思路是把 其他属性的值打包成一个类

package org.yla.thread;

import java.util.Random;

/**
 * 使用ThreadLocal类实现线程范围内的私有数据
 * 替代上节课map的作用
 * @author huo_chai_gun
 * 2014年12月18日下午3:25:35
 */
public class ThreadLocalTest {

	private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
	private static ThreadLocal<MyThreadLocalScopeDate> myLocalScopeData = new ThreadLocal<MyThreadLocalScopeDate>();
	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(100);
					System.out.println(Thread.currentThread().getName()+" has put data: "+data);
					//往local里面设置值
					threadLocal.set(data);
					MyThreadLocalScopeDate scopeDate = new MyThreadLocalScopeDate();
					scopeDate.setName("name "+data);
					scopeDate.setAge(data);
					myLocalScopeData.set(scopeDate);
					new A().get();
					new B().get();
				}
			}).start();
		}
	}
	
	static class A{
		public void get(){
			int data =threadLocal.get();
			System.out.println("A from "+Thread.currentThread().getName()+" has get data: "+data);
			MyThreadLocalScopeDate scopeDate=myLocalScopeData.get();
			System.out.println("A from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+scopeDate.getName()+" , age: "+scopeDate.getAge());
		}
	}
	
	
	static class B{
		public void get(){
			int data =threadLocal.get();
			System.out.println("B from "+Thread.currentThread().getName()+" has get data: "+data);
			MyThreadLocalScopeDate scopeDate=myLocalScopeData.get();
			System.out.println("B from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+scopeDate.getName()+" , age: "+scopeDate.getAge());
		}
	}
}

class MyThreadLocalScopeDate{
	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-0 has put data: 2
Thread-1 has put data: 94
A from Thread-1 has get data: 94
A from Thread-0 has get data: 2
A from Thread-1 has get MyThreadLocalScopeDate name: name 94 , age: 94
A from Thread-0 has get MyThreadLocalScopeDate name: name 2 , age: 2
B from Thread-1 has get data: 94
B from Thread-0 has get data: 2
B from Thread-1 has get MyThreadLocalScopeDate name: name 94 , age: 94
B from Thread-0 has get MyThreadLocalScopeDate name: name 2 , age: 2

上面的代码虽然实现了功能,但是代码实现是很垃圾,一个线程有一个实例,那么多个线程就有多个实例,所以我们还要对代码进行修改:

思路:利用单例模式 实现线程范围内的共享数据 这样子就永远只有一个对象 但是每个线程拿这个对象的时后我们让他显示互斥效果 这样子就节省了内容的消耗 并且外部调用的时候 还看不见ThreadLocal对这个对象进行了封装


真正开发中应该这么设计比较好【注意】

代码:

package org.yla.thread;

import java.util.Random;

/**
 * 使用ThreadLocal类实现线程范围内的私有数据
 * @author huo_chai_gun
 * 2014年12月18日下午3:25:35
 */
public class ThreadLocalTest {

	private static ThreadLocal<Integer> threadLocal = 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(100);
					System.out.println(Thread.currentThread().getName()+" has put data: "+data);
					//往local里面设置值
					threadLocal.set(data);
					//获取自己线程的MyThreadLocalScopeDate实例对象
					MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();
					myData.setName("name"+data);
					myData.setAge(data);
					new A().get();
					new B().get();
				}
			}).start();
		}
	}
	
	static class A{
		public void get(){
			int data =threadLocal.get();
			System.out.println("A from "+Thread.currentThread().getName()+" has get data: "+data);
			MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();
			System.out.println("A from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+myData.getName()+" , age: "+myData.getAge());
		}
	}
	
	
	static class B{
		public void get(){
			int data =threadLocal.get();
			System.out.println("B from "+Thread.currentThread().getName()+" has get data: "+data);
			MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();
			System.out.println("B from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+myData.getName()+" , age: "+myData.getAge());
		}
	}
}

class MyThreadLocalScopeDate{//单例模式
	
	private MyThreadLocalScopeDate(){};//构造方法私有化
	private static ThreadLocal<MyThreadLocalScopeDate> map = new ThreadLocal<MyThreadLocalScopeDate>();//封装MyThreadLocalScopeDate是线程实现范围内共享
	
	//思考AB两个线程过来的情况 自己分析 AB都需要的自己的对象 没有关系 所以不需要同步 如果有关系就需要同步了
	public static /*synchronized*/MyThreadLocalScopeDate getThreadInstance(){
		MyThreadLocalScopeDate instance =map.get();
		if(instance==null){
			instance = new MyThreadLocalScopeDate();
			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-0 has put data: 24
Thread-1 has put data: 13
A from Thread-1 has get data: 13
A from Thread-1 has get MyThreadLocalScopeDate name: name13 , age: 13
A from Thread-0 has get data: 24
A from Thread-0 has get MyThreadLocalScopeDate name: name24 , age: 24
B from Thread-1 has get data: 13
B from Thread-1 has get MyThreadLocalScopeDate name: name13 , age: 13
B from Thread-0 has get data: 24
B from Thread-0 has get MyThreadLocalScopeDate name: name24 , age: 24



多线程06_张孝祥-ThreadLocal类及应用技巧