线程的同步通信与线程范围内的数据共享问题
线程的同步通信与线程范围内的数据共享问题一、线程的同步通信
什么是线程的同步通信?他有什么作用?这是我们在看到一个新概念时多会想起的两个问题。线程的同步通信就是多个线程在做相关的事或者说在操作同一份数据时,线程之间建立一种互知的通信关系;它的作用是使线程之间能和睦共处,既其中某一线程做完这件事后,再通知另外的线程来做这件事,不出现混乱。如上一篇文章留下的面试问题就是一个很好的线程同步编程案例。下面给出详细的代码,和疑问解释。
public class CommunicationThread {final static Lock lock=new Lock();//实例化内部类public static void main(String args[]){new Thread(new Runnable() {public void run() {for(int i=1;i<=50;i++){lock.son(i);//调用子线程}}}).start();for(int i=1;i<=50;i++){lock.father(i);//调用父线程}}/* * Lock类:将相关的互斥操作放在同一个类中 */static class Lock{boolean flag=true;//两个互斥线程的通信钥匙public synchronized void son(int i){while(!flag){//判断是否是该线程运行,此处也可用if语句,效果相同 //但while语句可避免伪唤醒的情况发生,程序更安全。try {this.wait();//线程等待} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for(int j=1;j<=10;j++){System.out.println("son:"+j+"of current"+i);}flag=false;this.notify();//唤醒等待中的线程}public synchronized void father(int i){while(flag){try {this.wait();//线程等待} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for(int j=1;j<=100;j++){System.out.println("father:"+j+"of current"+i);}flag=true;this.notify();//唤醒等待中的线程}}}疑问:问什么要给已经互斥了的线程加上信息判断?这是为了防止电脑主机CPU介入线程的运行,当子线程运行结束之后本因该父线程运行,这时主机CPU就可能介入,再次让子线程来运行,这样就无法达到预期效果。所以在每个线程运行前都判断一下是否该自己运行了,不是的话就就“等待”,并且“唤醒”另外在等待中的线程。所以线程间的通信技术很有用。
----------------------------分割线-----------------------------------
二、线程范围内的数据数据问题:
这个技术点在java ee和底层框架中运用很多,所以很重要,很有必要去弄懂、弄清楚其中的原理。
下面就讲些我的理解:

上图线程1在运行时,调用A、B、C三个模块或对象,这三个模块处理的又是线程1绑定的同一个数据;线程2在运行时,也调用A、B、C三个模块或对象,这三个模块处理的又是线程2绑定的同一个数据,不再是先前线程1的数据了.这种原理就是线程范围内的数据共享,线程间的数据是不一样的,而线程内部运行的数据却一直是同一份。加入有1000个人同时访问一台服务器,这就得开设1000个线程,如果不运用上述原理,就会很混乱,数据调用出问题。所以,线程范围内的数据共享保证了别的线程无法干涉自己线程内部的数据,即使出了问题,也只是单方面的。
下面给出代码加以参考:
public class ShareData {private static int data=0;//静态全局变量public static void main(String[] args) {for(int i=0;i<2;i++){//创建两个线程new Thread(new Runnable(){public void run() {data=new Random().nextInt();System.out.println(Thread.currentThread().getName()+" has put data:"+data);new A().get();//模块A取得数据new B().get();//模块B取得数据}}).start();//线程开启}}//静态模块Astatic class A{public void get(){System.out.println("A from"+Thread.currentThread().getName()+" get data:"+data);}}//静态模块Bstatic class B{public void get(){System.out.println("B from"+Thread.currentThread().getName()+"get data:"+data);}}}运行结果:

上面的结果明显不适我们想要的。我们需要的是:模块A、B从第一个线程中取得数据相同而与模块A、B从第二个线程取得的数据不同。为什么得不到我们想要的结果呢?这里就是线程内部的数据共享出了问题,线程1调用的模块A、B取得了线程2的数据。那这个问题该怎么解决呢?
只要对上面的代码稍加处理就可以解决了:
public class ShareData {//建立哈希表,存取数据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(){public void run() {intdata=new Random().nextInt();//取得数据System.out.println(Thread.currentThread().getName()+" has put data:"+data);threadData.put(Thread.currentThread(), data);new A().get();//模块A取得数据new B().get();//模块B取得数据}}).start();//线程开启}}//静态模块Astatic class A{public void get(){int data = threadData.get(Thread.currentThread());System.out.println("A from"+Thread.currentThread().getName()+" get data:"+data);}}//静态模块Bstatic class B{int data = threadData.get(Thread.currentThread());public void get(){System.out.println("B from"+Thread.currentThread().getName()+"get data:"+data);}}}运行结果:

这时得到的结果就是预期想要的了,各线程间的数据互不影响,线程内部的数据能够共享。解决上述问题除了用哈希表外,还可以用ThreadLocal类,这个类的使用更加方便有效,有兴趣的人,可以尝试使用,下面就不给出参考代码了。
----------------------------------------分割线------------------------
线程同步问题现在告以段落了,以上2篇文章都是我在学习中遇到的疑问及理解,如有不足之处还请包含,同时也希望能给你带来些许帮助。