多线程同步互斥实例——使用synchronized实现线程通信和互斥
来源:互联网 发布:敲诈淘宝卖家减肥药 编辑:程序博客网 时间:2024/05/22 02:22
- 线程互斥概念
线程互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
- 实现线程同步互斥的四种方式
临界区(Critical Section):适合一个进程内的多线程访问公共区域或代码段时使用
互斥量 (Mutex):适合不同进程内多线程访问公共区域或代码段时使用,与临界区相似。
事件(Event):通过线程间触发事件实现同步互斥
信号量(Semaphore):与临界区和互斥量不同,可以实现多个线程同时访问公共区域数据,原理与操作系统中PV操作类似,先设置一个访问公共区域的线程最大连接数,每有一个线程访问共享区资源数就减一,直到资源数小于等于零。
- 实例说明线程同步和互斥
以一道面试题为例:
子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着在回到主线程循环100次,如此循环50次,请写出程序。
解题思路:
由题可知道,需要创建一个程序,然后创建两个线程(new Thread().start();)。在线程中,使用runnable 分别实现循环10次和100次。在将整个程序循环50次。则代码如下:
package cn.itcast.heima2;public class TraditionalThreadCommuniction {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {for (int j = 1; j <= 50; j++) {<span style="font-family: Arial, Helvetica, sans-serif;">//子程序循环50次</span>for (int i = 1; i <= 10; i++) {//执行10次输出子程序System.out.println("sub sthread sequece of " + i+ ",loop of" + j);}}}}).start();for (int j = 1; j <= 50; j++) {//主程序循环50次for (int i = 1; i <= 100; i++) {//执行100次输出主程序System.out.println("main sthread sequece of " + i+ ",loop of" + j);}}}}执行结果如下,从结果中,我们可以看到,这并不是我们要的结果。
主线程和子线程的执行都被打断了,所以 我们要把中间打印的循环代码保护起来。在这里,我们可以使用锁(synchronized), 实现主线程和子线程互相不被打断。可以使用TraditionalThreadSynchronized.class 。
则第一步改进代码如下:
package cn.itcast.heima2;public class TraditionalThreadCommuniction {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {for (int j = 1; j <= 50; j++) {synchronized (TraditionThradSynchronized.class) {for (int i = 1; i <= 10; i++) {System.out.println("sub sthread sequece of " + i+ ",loop of" + j);}}}}}).start();for (int j = 1; j <= 50; j++) {synchronized (TraditionThradSynchronized.class) {for (int i = 1; i <= 100; i++) {System.out.println("main sthread sequece of " + i+ ",loop of" + j);}}}}}
生成结果,虽然结果并非我们所期望的结果,但是,从结果中,我们可以看到,主线程和子线程已经实现了独立的执行,但是,并不能保证子线程和主线程交替出现,这怎么解决呢?
继续改进:
思路:我们可以把有关联的方法,集中到一个类中,这样是不是更好维护和更改呢?这就是高内聚的思想。即把相关联的方法放到同一个类上。所以,我们可以改造我们的类,生成一个类Business,其拥有两个方法,sub和main。则main方法中,放入主线程互斥的那部分代码;sub中放入子线程的互斥部分代码。然后再程序中分别调用这两个方法。
在business中,使用synchronized实现两个方法互斥。然后,在实现两个方法的交替出现。即实现主线程和子线程的互相通信。这样就非常简单,我们可以引入一个内部变量,bshouldSub ,如果bshouldSub是true,则执行子线程,否则等待。如果是flase则执行主线程,否则主线程等待。在执行主线程之后,将bshouldSub设置为true,并唤醒等待程序,子线程执行同理。则程序代码如下:
package cn.itcast.heima2;public class TraditionalThreadCommunictionn {public static void main(String[] args) {final Business business= new Business();new Thread(new Runnable() {@Overridepublic void run() {for (int j = 1; j <= 50; j++) {business.sub(j);}}}).start();for (int j = 1; j <= 50; j++) {business.main(j);}}}class Business{private boolean bshouldSub = true;//子线程和主线程通信信号public synchronized void sub(int j){if(!bshouldSub){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for (int i = 1; i <= 10; i++) {System.out.println("sub sthread sequece of " + i+ ",loop of" + j);}bshouldSub = false;//运行结束,设置值为FALSE 让主程序运行this.notify();//唤醒等待的程序}public synchronized void main(int j){if(bshouldSub){//如果bshouldsub=true ,等待 让子程序运行try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for (int i = 1; i <= 100; i++) {System.out.println("main sthread sequece of " + i+ ",loop of" + j);}bshouldSub = true;//让子程序运行this.notify();//唤醒等待的一个程序}}
由此程序,我们可以看到输出的结果为(由于篇幅限制,这里只截几张图来说明结果):
- 总结:
要用到共同数据(包括同类锁)或共同算法的若干方法应该归在同一个类身上,这种设计正好体现了高内聚和程序的健壮性。在解决线程的问题时,更多的从面相对象的思想上去思考问题和解决问题,会得到更好的效果。
1 0
- 多线程同步互斥实例——使用synchronized实现线程通信和互斥
- 多线程同步互斥实例——使用synchronized实现线程通信和互斥
- 多线程——线程同步互斥(synchronized)
- 2.使用synchronized关键字实现多线程的同步和互斥(不同线程同时读写同一数据)
- 多线程实例入门--利用互斥对象实现线程同步
- 使用互斥对象实现线程同步
- 线程同步与互斥 synchronized()
- 线程的同步互斥synchronized
- java基础——多线程(线程的同步互斥与通信)
- java基础——多线程(线程的同步互斥与通信)
- 多线程学习3-线程互斥与同步通信
- 【多线程】线程互斥之synchronized 详解
- java中的多线程——线程创建方式、线程互斥和线程间通信
- 线程互斥 Synchronized
- 多线程同步互斥实例——多个线程共享数据
- 多线程编程—线程的同步与互斥
- Windows多线程总结(3)-- 线程同步(使用互斥对象实现线程同步)
- 多线程互斥和同步
- 【Android】获取手机中已安装apk文件信息(PackageInfo、ResolveInfo)(应用图片、应用名、包名等)
- 图解oracle jdeveloper中创建BPM审批页面
- 设计模式笔记——单例模式
- 设计模式笔记:单例模式
- Java并发编程:并发容器之CopyOnWriteArrayList(转载)
- 多线程同步互斥实例——使用synchronized实现线程通信和互斥
- OD破解Crackme1.exe密码
- android /Cordova LOG 、console 调试调试打印log
- struts1单例线程不安全struts2多例线程安全
- 永久关闭linux防火墙
- C/C++预习:数字逆序输出(2,折半)
- Argument list too long 参数太长问题
- 图解oracle jdeveloper 代码智能提示+字体+编码 配置方法
- 判断手机网络状态