- 浏览: 13326 次
- 性别:
最新评论
线程的同步通信与线程范围内的数据共享问题
一、线程的同步通信
什么是线程的同步通信?他有什么作用?这是我们在看到一个新概念时多会想起的两个问题。线程的同步通信就是多个线程在做相关的事或者说在操作同一份数据时,线程之间建立一种互知的通信关系;它的作用是使线程之间能和睦共处,既其中某一线程做完这件事后,再通知另外的线程来做这件事,不出现混乱。如上一篇文章留下的面试问题就是一个很好的线程同步编程案例。下面给出详细的代码,和疑问解释。
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 block e.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 block e.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();//线程开启 } } //静态模块A static class A{ public void get(){ System.out.println("A from"+Thread.currentThread().getName() +" get data:"+data); } } //静态模块B static 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() { int data=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();//线程开启 } } //静态模块A static class A{ public void get(){ int data = threadData.get(Thread.currentThread()); System.out.println("A from"+Thread.currentThread().getName() +" get data:"+data); } } //静态模块B static class B{ int data = threadData.get(Thread.currentThread()); public void get(){ System.out.println("B from"+Thread.currentThread().getName() +"get data:"+data); } } }
运行结果:
这时得到的结果就是预期想要的了,各线程间的数据互不影响,线程内部的数据能够共享。解决上述问题除了用哈希表外,还可以用ThreadLocal类,这个类的使用更加方便有效,有兴趣的人,可以尝试使用,下面就不给出参考代码了。
----------------------------------------分割线------------------------
线程同步问题现在告以段落了,以上2篇文章都是我在学习中遇到的疑问及理解,如有不足之处还请包含,同时也希望能给你带来些许帮助。
发表评论
-
多线程初谈——线程的创建与互斥问题
2013-10-01 18:13 1398多线程初谈——线程的创建与互斥 对于线程起初也很是不 ... -
网络通信见解之谈
2013-07-17 13:38 614一、网络通信的基本原理 现如今,出现了各式各样的聊天平 ... -
简单的bmp文件打开与保存
2013-07-01 22:24 880简单的bmp文件打开与保 ... -
分形浅谈——科赫曲线和L-System
2013-06-24 22:47 1230分形浅谈开始接触到分行图时,感觉很难,无法下手,只能做出第一层 ... -
对关键字final、static的理解
2013-05-10 23:36 532一、final关键字 fin ... -
对关键字的理解——访问权限
2013-05-10 16:17 595关键字public、pr ... -
队列的定义及运用
2013-03-23 14:58 638队列简称队,是限制在表的一端进行插入操作,而在表的另一端进行删 ... -
重绘方法的重写利用
2013-03-22 21:44 614重绘是为了在画布上保留原始痕迹的一种方法,他的目的是用来保存你 ... -
数组的定义及递归的运用
2013-03-22 21:43 1019一、数组有一维数组、 ... -
监听器与变量的作用域
2013-03-22 21:41 702监听器是用来实现一些可控操作的工具,如你在打开一个QQ界面的时 ... -
java中的继承
2013-03-08 00:31 564Java中的接口 什么是接口?不是以class定义的类而是以i ... -
Java中类的继承、重写、自动转型以及多态
2013-03-06 01:13 714Java中类的继承、重写、自动转型以及多态 1) 类的继承 在 ... -
java的构造器方法、方法重载和引用传递
2013-03-04 23:55 727Java的构造器方法、方法重载与引用传递 一、 构造器方法 构 ... -
JAVA语言中的类与对象
2013-03-04 00:08 726Java语 ...
相关推荐
互斥体Mutex和事件对象EventWaitHandler属于内核对象,利用内核对象进行线程同步,线程必须要在用户模式和内核模 式间切换,所以一般效率很低,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个...
原版自1993年出版第1版到2003年出版第2版以来,已在世界范围内被广泛地采用为高等院校本科生和研究生的教材或参考书。 第1章 并行计算介绍 1.1 推动并行化 1.1.1 计算能力因素——从晶体管到浮点运算速度 1.1.2 ...
控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。 2.尽量避免随意使用静态变量 要知道,当某个对象被定义为stataic的变量所引用,那么GC通常是不会回收这个对象所占有的内存,如 ...
2.任务同步和互斥:STM32FreeRTos提供了任务同步和互斥的功能,可以实现多个任务之间的协作和共享数据。3.定时器和时钟管理:STM32FreeRTos提供了定时器和时钟管理的功能,能够按照预设的时间周期定时触发相应的任务...
例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望...
例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望...
实例239 查询日期控件内数据 实例240 控件作为字段、操作符和内容进行查询 实例241 巧妙获取年龄 实例242 格式化金额 实例243 如何随机显示记录 9.3 查询前若干名数据 实例244 查询前10名数据 实例245 取出...
实例239 查询日期控件内数据 实例240 控件作为字段、操作符和内容进行查询 实例241 巧妙获取年龄 实例242 格式化金额 实例243 如何随机显示记录 9.3 查询前若干名数据 实例244 查询前10名数据 实例245 取出...
7.4 多处理器同步问题 7.4.1 唤醒丢失问题 7.4.2 巨群问题 7.5 信号灯 7.5.1 提供互斥访问的信号灯 7.5.2 使用的信号灯的事件等待 7.5.3 用于控制可计数资源的信号灯 7.5.4 信号灯的缺点 7.5.5 护卫 7.6 自旋锁 ...
cc实例184 执行一个外部程序直到其结束 cc实例185 调用具有参数的可执行程序 6.7 线程同步 cc实例186 利用事件对象实现线程同步 cc实例187 利用互斥对象实现线程同步 cc实例188 利用临界区实现线程同步 ...
多线程,用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用? 59.使用socket建立客户端与服务器的通信的过程 60.JAVA语言国际化应用,Locale类,Unicode 61.描述反射机制的作用 62.如何读写一个...
cc实例239 查询日期控件内数据 cc实例240 控件作为字段.c操作符和内容进行查询 cc实例241 巧妙获取年龄 cc实例242 格式化金额 cc实例243 如何随机显示记录 9.3 查询前若干名数据 cc...
cc实例239 查询日期控件内数据 cc实例240 控件作为字段.c操作符和内容进行查询 cc实例241 巧妙获取年龄 cc实例242 格式化金额 cc实例243 如何随机显示记录 9.3 查询前若干名数据 cc...
11.3.2 线程同步 317 11.4 一个多线程的示范程序 325 11.4.1 用户界面 326 11.4.2 搜索线程 330 11.4.3 调整优先级 334 11.5 多线程与数据库 335 11.6 多线程与图形处理 340 11.7 总结 343 第12章 文件处理 344 12.1...
其中包括文件、文件映射、进程、线程、安全和同步对象等 CompareFileTime 对比两个文件的时间 CopyFile 复制文件 CreateDirectory 创建一个新目录 CreateFile 打开和创建文件、管道、邮槽、通信服务、设备以及...
获取足够多的问题领域的知识,需求抽取的方法一般有问卷法、面谈法、数据采集法、用例法、情景实例法以及基于目标的方法等;还有知识工程方法,例如,场记分析法、卡片分类法、分类表格技术和基于模型的知识获取等 ...
14.4 继承中关于属性的一些问题.169 14.5 小 结 .172 第四部分 深入了解 C#.174 第十五章 接 口 .174 15.1 组件编程技术 .174 15.2 接 口 定 义 .177 15.3 接口的成员 .178 15.4 接口的实现 .182 ...