多线程学习--线程内共享对象ThreadLocal

线程内共享数据ThreadLocal的使用

1、说明:

每个当前线程中都有一个ThreadLocal,这个ThreadLocal是与其他线程分开的。存储在ThreadLocal是数据,对于线程内共享是共享的,线程外(其它线程)是独立的。

2、线程内共享数据的两种场景(共享一个or多个变量)

(1)场景一:线程内只需共享一个变量
  • 方法一:定义private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();变量,存储每个线程是共享变量。
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * 线程数据共享demo(线程内共享变量,线程外独立)
 * 
 * 方法一:定义Map<Thread, Integer>对象,存储共享数据
 */
public class ThreadScopeShareData {

	private static int data = 0;
	// 存储每个线程中独立的数据
	private static Map<Thread, Integer> threadData = 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() {
					data = new Random().nextInt();
					threadData.put(Thread.currentThread(), data); // 将当前线程的线程和线程共享数据存入map中
					System.out.println(Thread.currentThread().getName() + "has put data:" + data);
					new A().get(); // 调用模块一的方法
					new B().get(); // 调用模块二的方法
				}
			}).start();
		}
	}

	// 模块一
	static class A {
		public void get() {
			int data = threadData.get(Thread.currentThread()); // 从map中获取当前线程数据对象
			System.out.println("A from " + Thread.currentThread().getName() + " get data:" + data);
		}
	}
	// 模块二
	static class B {
		public void get() {
			int data = threadData.get(Thread.currentThread()); // 从map中获取当前线程数据对象
			System.out.println("B from " + Thread.currentThread().getName() + " get data:" + data);
		}
	}
}
  • 方法二:使用ThreadLocal。
import java.util.Random;

/**
 * 线程数据共享demo(ThreadLocal:线程内共享变量,线程外独立)
 * 
 * 场景一:线程内只需共享一个变量
 * 方法二:使用ThreadLocal
 */
public class ThreadLocalTest1 {

	// 创建一个ThreadLocal对象
	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);
					x.set(data); // 将当前线程的数据放入ThreadLocal
					new A().get(); // 调用模块一的方法
					new B().get(); // 调用模块二的方法
				}
			}).start();
		}
	}

	// 模块一
	static class A {
		public void get() {
			int data = x.get();// 获取当前线程的数据
			System.out.println("A from " + Thread.currentThread().getName() + " get data:" + data);
		}
	}

	// 模块二
	static class B {
		public void get() {
			int data = x.get();// 获取当前线程的数据
			System.out.println("B from " + Thread.currentThread().getName() + " get data:" + data);
		}
	}
}

(2)场景二:线程内需共享多个变量
  • 方法一:定义一个共享数据结构的类,将共享数据结构类作为ThreadLocal的泛型
import java.util.Random;

/**
 * 线程数据共享demo(ThreadLocal:线程内共享变量,线程外独立)
 * 
 * 场景二:线程内需共享多个变量
 * 方法一:定义一个共享数据结构的类,将共享数据结构类作为ThreadLocal的泛型
 */
public class ThreadLocalTest2 {

	// 创建一个ThreadLocal对象,并将MyThreadScopeData1座位泛值类型
	private static ThreadLocal<MyThreadScopeData1> myThreadScopeData = new ThreadLocal<MyThreadScopeData1>();

	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);
					// 设置当前线程的数据对象,并且将对象放置在ThreadLocal对象中
					MyThreadScopeData1 myData = new MyThreadScopeData1();
					myData.setName(Thread.currentThread().getName());
					myData.setAge(data);
					myThreadScopeData.set(myData);
					new A().get();
					new B().get();
				}
			}).start();
		}
	}

	// 模块一
	static class A {
		public void get() {
			MyThreadScopeData1 myData = myThreadScopeData.get(); // 获取当前线程数据对象
			System.out.println("A from " + Thread.currentThread().getName() + ":  getName()=" + myData.getName()
					+ ", getAge()=" + myData.getAge());

		}
	}

	// 模块二
	static class B {
		public void get() {
			MyThreadScopeData1 myData = myThreadScopeData.get(); // 获取当前线程数据对象
			System.out.println("B from " + Thread.currentThread().getName() + ":  getName()=" + myData.getName()
					+ ", getAge()=" + myData.getAge());
		}
	}
}

/**
 * 定义共享数据结构类
 */
class MyThreadScopeData1 {
	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对象放入共享数据结构的类中,在共享数据结构类中存储所有线程的共享数据

import java.util.Random;

/**
 * 线程数据共享demo(ThreadLocal:线程内共享变量,线程外独立)
 * 
 * 场景二:线程内需共享多个变量 
 * 方法二:定义一个共享数据结构的类,ThreadLocal对象放入共享数据结构的类中,在共享数据结构类中存储所有线程的共享数据
 */
public class ThreadLocalTest3 {
	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的实例,再设置值
					MyThreadScopeData.getThreadDataInstance().setName(Thread.currentThread().getName());
					;
					MyThreadScopeData.getThreadDataInstance().setAge(data);
					new A().get(); // 调用模块一的方法
					new B().get(); // 调用模块二的方法
				}
			}).start();
		}
	}

	// 模块一
	static class A {
		public void get() {
			MyThreadScopeData myData = MyThreadScopeData.getThreadDataInstance(); // 获取当前线程的共享数据对象
			System.out.println("A from " + Thread.currentThread().getName() + ":  getName()=" + myData.getName()
					+ ", getAge()=" + myData.getAge());

		}
	}

	// 模块二
	static class B {
		public void get() {
			MyThreadScopeData myData = MyThreadScopeData.getThreadDataInstance(); // 获取当前线程的共享数据对象
			System.out.println("B from " + Thread.currentThread().getName() + ":  getName()=" + myData.getName()
					+ ", getAge()=" + myData.getAge());
		}
	}
}

/**
 * 定义共享数据结构类,类中定义ThreadLocal对象,将所有线程的共享数据都放置这个类的这个对象中
 */
class MyThreadScopeData {
	private String name;
	private int age;

	// private static MyThreadScopeData instance = null;
	private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();

	// 步骤1、构建私有构造函数,不允许外部通过new创建
	private MyThreadScopeData() {
	};

    // 步骤2、开放获取实例的方法
	public static MyThreadScopeData getThreadDataInstance() {
		MyThreadScopeData instance = map.get();
		if (null == instance) {
			instance = new MyThreadScopeData();
			map.set(instance);
		}
		return instance;
	}

	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;
	}
}

3、总结:

在线程内需共享多个变量中推荐使用方法二,这种将ThreadLocal对象定义在共享数据结构类的方式将使代码更加优雅。

猜你喜欢

转载自my.oschina.net/u/3696939/blog/1819390