java并发编程(对于线程内共享变量安全的思考)

 

        上一篇博客讲解了,多个线程之间的互斥和同步的操作,一个是利用了锁的技术;另一个内则是利用了Object的notify和wait来实现同步操作。这篇博客呢,来谈一下对于线程内变量的安全问题。


        经典的三层架构,我们都应该比较的熟知,分别是表现层—业务逻辑层——数据访问层。那么问题来了,我们如何来保证我们的业务逻辑层来维持同一个数据库连接对象呢?

 

<span style="font-family:Comic Sans MS;font-size:18px;">package com.test;

import java.util.Random;

public class ThreadScopeShareData {

	//用一个对象来模仿,数据库连接对象操作
	private static int data = 0;  
     
    public static void main(String[] args) {  
        //循环方式共启动8个线程  
        for(int i=0;i<8;i++){  
            //启动一个线程  
            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()   
                    + " get data :" + data);  
        }  
    }  
      
    static class B{  
        public void get(){           
            System.out.println("B from " + Thread.currentThread().getName()   
                    + " get data :" + data);  
        }         
    }  
}
</span>


        上述例子总,一共启动了8个线程,每次都会去获取新的随机数,类似于我们每次都会获取新的数据库连接对象操作。针对于上面的例子,可想而知,肯定是不可以的,保证不了线程内变量的安全,那么我们怎么办呢?


        想法一

        把每个线程的变量单独放置在一个地方,获取的时候,根据线程的标识去获取。说白了就是把每个线程创建的变量单独存起来,找的时候,还找他。因此我们可以采取map的方式来实现,也就这样来操作。

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

 

        具体看下面的代码


<span style="font-family:Comic Sans MS;font-size:18px;">package com.test;

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

public class ThreadScopeShareData {

	 private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();  
     
	    public static void main(String[] args) {  
	        //共启动2个线程  
	        for(int i=0;i<8;i++){  
	            //启动一个线程  
	            new Thread(new Runnable(){  
	                @Override  
	                public void run() {  
	                    int data = new Random().nextInt();  
	                    System.out.println(Thread.currentThread().getName()   
	                            + " has put data :" + data);  
	                    //以当前线程为key值放入到map中,当取值时根据各自的线程取各自的数据  
	                    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()   
	                    + " get data :" + data);  
	        }  
	    }  
	      
	    static class B{  
	        public void get(){  
	            int data = threadData.get(Thread.currentThread());            
	            System.out.println("B from " + Thread.currentThread().getName()   
	                    + " get data :" + data);  
	        }         
	    }  
}
</span>


        上面就是把每个线程创建的变量放置到单独的一个地方,也就是map中,到时候根据线程标识去map中寻找。


        想法二

        其实在java中已经为我们提供好了类 ThreadLocal<T>,该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其getset 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。 


       有了ThreadLocal,上面的代码就变得容易起来,直接调用相应的set和get方法即可。

<span style="font-family:Comic Sans MS;font-size:18px;">package com.test;

import java.util.Random;

public class ThreadScopeShareData {

	//通过ThreadLocal来存取线程内的变量
	private static ThreadLocal<Integer> threadData=new ThreadLocal<Integer>();
    
	    public static void main(String[] args) {  
	        //共启动8个线程  
	        for(int i=0;i<8;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.set(data);
	                    new A().get();  
	                    new B().get();  
	                }  
	            }).start();  
	        }  
	    }  
	      
	    static class A{  
	        public void get(){  
	        	//从当前线程中进行获取放置的线程变量
	            int data = threadData.get();
	            System.out.println("A from " + Thread.currentThread().getName()   
	                    + " get data :" + data);  
	        }  
	    }  
	      
	    static class B{  
	        public void get(){  
	        	 int data = threadData.get();         
	            System.out.println("B from " + Thread.currentThread().getName()   
	                    + " get data :" + data);  
	        }         
	    }  
}
</span>

        通过ThreadLocal,就可以方便的实现,多个线程之间的变量的安全,但是,我们也发现一个ThreadLocal只能存取一个变量,那么多个变量如何来操作呢?


        这时候我们换一个思路不就可以了吗?ThreadLocal可以放置变量,也绝对可以放置对象哈!我们把需要放置的变量封装成一个对象不就可以了吗?或者封装到集合,只要打包就可以了哈!具体的代码小编就不在多说了。


  





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值