线程范围内共享变量的概念与作用以及ThreadLocal类及应用修复bug

    关于线程范围内的变量共享,这种应用场景,在实际开发中应用不是很多,但对理解和加深多线程编程却有很大的好处!这里在网上找了一些资料,收藏仅供以后学习:创建两个个线程,他们都访问同一个变量,要求同一个线程设置的值只能被自身所获取!

package dhp.com.test;

import java.util.Random;

public class ThreadScopeShareData {
     private static int data = 0;
     
     public static void main(String[] args) {
            new Thread( new Runnable() {
                
                 @Override
                 public void run() {
                      data = new Random().nextInt();
                     System. out.println(Thread. currentThread().getName()
                                + " has put data:"+ data);
                      new A().get();
                      new B().get();
                }
           }).start();
     }
     static class A {
            public void get() {
                System. out.println( "A from "+Thread.currentThread ().getName()
                           + " has put data:"+ data);
           }
     }
     static class B {
            public void get() {
                System. out.println( "B from "+Thread.currentThread ().getName()
                           + " has put data:"+ data);
           }
     }
}

输出结果:


如果new 两个线程

for (int i = 0; i < 2; i++) {
                 new Thread( new Runnable() {
                     
                      @Override
                      public void run() {
                            data = new Random().nextInt(1000);
                          System. out.println(Thread. currentThread().getName()
                                     + " has put data:"+ data);
                            new A().get();
                            new B().get();
                     }
                }).start();
输出结果:


从结果中可以看出Thread-0该线程设置的值并没有被与该线程相关的类读取到!这使什么原因呢,这是因为,线程Thread-0刚把data设置值之后,还没来得及输出该值就被下个线程给改变了!所以线程一读取不到它自己设置的值!有可能甚至会出现Thread-0 has put data 和 Thread-1 has put data输出值相等的情况。 

改进:用于存放当前的   线程  以及   值

 private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();

完整代码:

package dhp.com.test;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

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() {
					int data = new Random().nextInt(1000);
					System.out.println(Thread.currentThread().getName()
							+ " has put data:"+ data);
					
					threadData.put(Thread.currentThread(), data);
					
					new A().get();
					new B().get();
				}
			}).start();
		}
		
	}
	static class A {
		public void get() {
			int data = threadData.get(Thread.currentThread());
			System.out.println("A from "+Thread.currentThread().getName()
					+ " has put data:"+ data);
		}
	}
	static class B {
		public void get() {
			int data = threadData.get(Thread.currentThread());
			System.out.println("B from "+Thread.currentThread().getName()
					+ " has put data:"+ data);
		}
	}
}



但有时会报错:


这体现出hashMap不是线程安全的。

我们可以利用ThreadLocal 来修复这个bug:

package dhp.com.test;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class ThreadLocalTest {
     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(1000);
                         System.out.println(Thread.currentThread().getName()
                                   + " has put data:"+ data);
                        
                         x.set(data);
                        
                         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()
                         + " has put data:"+ data);
          }
     }
     static class B {
          public void get() {
               int data = x.get();
               System.out.println("B from "+Thread.currentThread().getName()
                         + " has put data:"+ data);
          }
     }
}

其上实例是线程范围内变量共享的真实写照,上代码逻辑并不能于理解,需要注意的是data不是定义成了类变量了嘛,干嘛还要在此用一个方法的成员变量来覆盖!首先还得回到第一个实例,因为如果定义成类变量会出现第一个线程刚设置值马上又被第二个线程覆盖这种情况,所以才在方法里定义成方法的局部变量,每条线程会为各自的run方法分配各自的存储空间用于存储各自方法内部的局部变量,当这个方法结束时,分配给这个方法的栈就会被释放,栈中变量也会消失!而且很大程度上节省了内存!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值