什么叫线程范围内的共享数据(线程外独立)?
一个线程在运行的时候可以调用A模块,B模块,C模块,就比如我们调用A,B,C三个对象,A,B,C三个模块内部的代码就要访问外面的变量,那么此时如果我们把ABC调用的那个变量设置成static的静态变量,我们也可以实现让ABC同时访问同一个变量,但是如果我们用第二个线程去同时调用ABC去访问这个变量,这时候第二个线程访问到的这个变量就不是刚才我们线程1所访问的变量了!!!而是另外一个数据,也就是说static的变量在被同一个线程访问的时候这个变量是相同的,当我们换了线程访问,那么这个数据就不同了。那如果我们是5个线程访问这个变量,那么我们就会得到5个不同的变量。
public class ThreadScopShareData {
private static int data = 0;//我们定义一个静态变量data
static class A{//定义一个静态内部类
public void getData(){
System.out.println(Thread.currentThread().getName()+"从A中得到数据"+data);
}
}
static class B{//定义第二个静态内部类
public void getData(){
System.out.println(Thread.currentThread().getName()+"从B中得到数据"+data);
}
}
public static void main(String[] args) {
//在主函数中创建两个线程
for(int i=1;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
data =new Random().nextInt();
System.out.println(Thread.currentThread().getName()+"已经设置了数据"+data);
new A().getData();
new B().getData();
}
}).start();
}
}
}
我们运行上面的程序会发现结果如下
Thread-0已经设置了数据9296023
Thread-1已经设置了数据979192099
Thread-0从A中得到数据979192099
Thread-1从A中得到数据979192099
Thread-0从B中得到数据979192099
Thread-1从B中得到数据979192099
Thread-1已经设置了数据979192099
Thread-0从A中得到数据979192099
Thread-1从A中得到数据979192099
Thread-0从B中得到数据979192099
Thread-1从B中得到数据979192099
线程0设置的数据和线程0取得的数据是不同的,所以这里的数据就没有实现线程内的共享!
ThreadLocal就相当于一个map
现在我们把上面的程序改写一下
public class ThreadScopShareData {
private static int data = 0;//我们定义一个静态变量data
private static Map<Thread, Integer> threadData = new HashMap<Thread,Integer>();
static class A{//定义一个静态内部类
public void getData(){
int data = threadData.get(Thread.currentThread());
System.out.println(Thread.currentThread().getName()+"从A中得到数据"+data);
}
}
static class B{//定义第二个静态内部类
public void getData(){
int data = threadData.get(Thread.currentThread());
System.out.println(Thread.currentThread().getName()+"从B中得到数据"+data);
}
}
public static void main(String[] args) {
//在主函数中创建两个线程
for(int i=1;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data =new Random().nextInt();
threadData.put(Thread.currentThread(), data);
System.out.println(Thread.currentThread().getName()+"已经设置了数据"+data);
new A().getData();
new B().getData();
}
}).start();
}
}
}
我们创建一个map,然后为每个线程创建一个局部变量,然后以线程的名字单做key保存在线程中,这样我们会获得下面的结果
Thread-1已经设置了数据-1254485186
Thread-0已经设置了数据1394718209
Thread-1从A中得到数据-1254485186
Thread-0从A中得到数据1394718209
Thread-1从B中得到数据-1254485186
Thread-0从B中得到数据1394718209
Thread-0已经设置了数据1394718209
Thread-1从A中得到数据-1254485186
Thread-0从A中得到数据1394718209
Thread-1从B中得到数据-1254485186
Thread-0从B中得到数据1394718209
我们发现此时线程1和线程2的这个变量相互独立了。
ThreadLocal
首先ThreadLocal和本地线程没有一毛钱关系,更不是一个特殊的Thread,它只是一个线程的局部变量(其实就是一个Map),ThreadLocal会为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。这样做其实就是以空间换时间的方式(与synchronized相反),以耗费内存为代价,单大大减少了线程同步(如synchronized)所带来性能消耗以及减少了线程并发控制的复杂度。
我们把上面的程序改成ThreadLocal实现
Thread-0已经设置了数据-732021060
Thread-1已经设置了数据712253571
Thread-1从A中得到数据712253571
Thread-0从A中得到数据-732021060
Thread-1从B中得到数据712253571
Thread-0从B中得到数据-732021060
public class ThreadScopShareData {
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
public static void main(String[] args) {
//在主函数中创建两个线程
for(int i=1;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data =new Random().nextInt();
threadLocal.set(data);
System.out.println(Thread.currentThread().getName()+"已经设置了数据"+data);
new A().getData();
new B().getData();
}
}).start();
}
}
static class A{//定义一个静态内部类
public void getData(){
System.out.println(Thread.currentThread().getName()+"从A中得到数据"+threadLocal.get());
}
}
static class B{//定义第二个静态内部类
public void getData(){
threadLocal.get();
System.out.println(Thread.currentThread().getName()+"从B中得到数据"+threadLocal.get());
}
}
}
运行结果
Thread-0已经设置了数据-732021060
Thread-1已经设置了数据712253571
Thread-1从A中得到数据712253571
Thread-0从A中得到数据-732021060
Thread-1从B中得到数据712253571
Thread-0从B中得到数据-732021060
多个变量怎么用ThreadLocal存储?
一个ThreadLocal就代表一个变量,那么要是想在一个线程中存储多个变量的时候怎么存储呢 ?
此时我们可以把多个变量封装成一个对象,然后把这个对象存储在ThreadLocal中就可以实现我们的需求了。。
我们把上面的代码改写一下,让我们的ThreadLocal可以存放多个变量,并且每个线程的ThreadLocal都是独立的。
/**
*
*
* ThreadScopShareData
* 创建人:LBM
* 时间:2016年11月24日-下午3:03:03
* @version 1.0.0
*
*/
public class ThreadScopShareData {
public static void main(String[] args) {
A a = new A();
B b = new B();
// 在主函数中创建两个线程
for (int i = 1; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
LocalData.getInstance().setAge(data);//创建自己的对象存放变量
LocalData.getInstance().setName("name"+data);//创建自己的对象存放变量
System.out.println(Thread.currentThread().getName() +data);
a.getData();
b.getData();
}
}).start();
}
}
static class A {// 定义一个静态内部类
public void getData() {
LocalData localData =LocalData.getInstance();//创建自己线程内部的对象去获得变量
System.out.println(Thread.currentThread().getName() + "从A中得到数据" + "age===" + localData.getAge()
+ "name===" + localData.getName());
}
}
static class B {// 定义第二个静态内部类
public void getData() {
LocalData localData =LocalData.getInstance();//创建自己线程内部的对象去获得变量
System.out.println(Thread.currentThread().getName() + "从B中得到数据" + "age===" + localData.getAge()
+ "name===" + localData.getName());
}
}
}
/**
*
* 我们从线程的任意地方调用我的这个对象,都会得到和该线程相关的一个实例对象。
* LocalData
* 创建人:LBM
* 时间:2016年11月24日-下午3:03:21
* @version 1.0.0
*
*/
class LocalData {//创建一个对象
private LocalData() {// 构造方法私有化
}
public static LocalData getInstance() {
LocalData localData = threadLocal.get();//当我们从当前线程中的ThreadLocal中拿不到对象的时候我们就创建新的对象
if (localData == null) {
localData = new LocalData();
threadLocal.set(localData);
}
return localData;
}
//在对象内部创建一个ThreadLocal,这样当每个线程来创建对象的时候,创建的都是这个线程自己内部的对象
private static ThreadLocal<LocalData> threadLocal = new ThreadLocal<LocalData>();
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封装在这个对象内部,然后通过单例模式的思想就实现了无论在线程的哪里调用这个对象,所得到的对象都是和这个线程相关的对象!每个线程调用getInstance创建对象的时候,都会进行判断,该线程是否存在这个对象,如果存在直接返回,如果不存在,创建一个新的对象。