几个并发编程的例子
在这里讨论一下自己遇到的几个自己感觉比较好的并发编程的例子。如果读者已经完全明白是怎么回事,请略过。
例一:
先看如下程序,想一下这个程序多长时间结束?
- import java.util.concurrent.TimeUnit;
- public class Stop {
- private static boolean isStop = false;
- public static void main(String[] args) throws Exception {
- Thread thread = new Thread(new Runnable(){
- public void run(){
- int count = 0;
- while(!isStop){
- count++;
- }
- System.out.println("循环结束,此时count值为:" + count);
- }
- });
- thread.start();
- TimeUnit.SECONDS.sleep(1);
- isStop = true;
- }
- }
在我的机器上,这个程序永远停不下来!你也可以在自己的机器上试一下。
这是为什么呢?
原因是:虽然在主线程中修改了isStop的值,但是在线程thread中永远看不到修改后的值,虽然循环在执行,在进行检测。在《Effective Java》中我们可以看到这样的解释,由于没有同步,虚拟机将这个代码:
- while(!isStop){
- count++;
- }
转变成了这样:
- if(!isStop){
- while(true){
- count++;
- }
- }
修正这个问题的一种方式是,同步访问isStop这个域,这样程序才会如期停止。在上面的程序中添加如下代码片段即可:
- private static synchronized void stop(){
- isStop = true;
- }
- private static synchronized boolean stoped(){
- return isStop;
- }
其实在上面我们可以看到,上面的方法即使没有被同步也是原子的,但是这里为什么要这么做呢,原因只是为了synchronized的通信效果,而不是互斥访问。
还一种修改方式更为简洁,只需要将isStop声明为volatile即可,这样上面的同步方法即可略去,volatile可以保证任何一个线程在读取该域的时候都将看到最近被写入的值。
例二:
上面提到了volatile,我们可以再看一个使用它的例子,如下:
- private static volatile int number = 0;
- public static int nextNumber(){
- return number++;
- }
上面这个方法的目的是让每个调用都返回不同的值,但是不要超过int的范围。但是上面的这个方法是无法正常工作的,问题出现在哪呢?问题出现在递增操作符(++)不是原子的。这个操作在number域中执行两项操作,首先读取值,然后再写入新的值。如果一个线程在另一个线程读取旧值和写回新值的这个期间读取这个域,那么两个线程看到的是同一个值,所以会返回相同的值。
对于这个我们的修改方式就是使用synchronized关键字,这样可以保证不会出现交叉调用的出现,或是使用java.util.concurrent.atomic的一部分来达到效果。
例三:
下面再看这样一个程序,它最后会保证a,b两个数字相同吗?
- import java.io.IOException;
- public class MThread{
- public static void main(String[] args) throws IOException{
- ShareObject so = new ShareObject();
- Thread thread1 = new Thread(new ThreadOperation(so,"add"));
- Thread thread2 = new Thread(new ThreadOperation(so,"sub"));
- thread1.setDaemon(true);
- thread2.setDaemon(true);
- thread1.start();
- thread2.start();
- System.out.println("按Enter键结束!");
- System.in.read();
- System.out.println("此时的so里面的a,b分别为a="+so.a+"b="+so.b);
- }
- }
- class ThreadOperation implements Runnable{
- private String operation;
- private ShareObject so;
- public ThreadOperation(ShareObject so,String oper){
- this.operation = oper;
- this.so = so;
- }
- public void run() {
- while(true){
- if(operation.equals("add")){
- so.add();
- }else{
- so.sub();
- }
- }
- }
- }
- class ShareObject{
- int a = 100;
- int b = 100;
- public synchronized void add(){
- ++a;
- ++b;
- }
- public synchronized void sub(){
- --a;
- --b;
- }
- }
经过我自己的运行,运行出来的a,b的值相差很大,如下所示:
此时的so里面的a,b分别为 a=4553016b=4552099
这是为什么呢?我再来一个更迷惑的解决方法,我们可以试着给run()方法里面执行完加或者减操作后添加一个停止很短时间的代码,结果输出就会正确!添加后如下:
- public void run() {
- while(true){
- if(operation.equals("add")){
- so.add();
- }else{
- so.sub();
- }
- try {
- TimeUnit.MILLISECONDS.sleep(1);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
相关推荐
T型三电平+SVPWM的下垂控制与双闭环中点电位平衡控制.pdf
STM32真实企业级项目:锅炉控制器源码、原理图与PCB图.pdf
STM32F103 Modbus主站源码:正常使役,支持多从机功能码通信及从机寄存器写入.pdf
Simulink永磁同步直驱风机PMSG一次调频离散模型:含虚拟惯性与下垂控制,可扩展至光伏储能研究.pdf
VSG仿真、并网与离网运行仿真、预同期并网控制及虚拟同步机逆变器仿真.pdf
VIC水文模型全程视频教学指导.pdf
vrep_coppeliasim+matlab机器人轨迹控制仿真:利用matlab读取轨迹并控制机械臂在墙上绘图的详细学习示例.pdf
2000-2022年上市公司行业异质性数据(技术密集型、劳动密集型、资本密集型)(含原始数据和处理代码) 1、时间:2000-2022年 2、指标:股票代码、年份、股票简称、统计日期、行业名称、行业代码、成立日期、上市日期、所在省份、所在城市、上市状态、保留两位行业代码、保留一位行业代码、高科技为1,非高科技为0、重污染为1,非重污染为0、制造业为1,非制造业为0、劳动密集型为1,资本密集型为2,技术密集型为3 3、来源:csmar 4、根据2012年中国证监会行业划分是否高科技、是否重污染、是否制造业、是否劳动密集型、资本密集型、技术密集型。 5、内容:包括原始数据、处理代码和计算结果
TMS320F28335电机控制程序:BLDC、PMSM无感有感及异步VF程序源代码与开发资料大全.pdf
tc275、s12x、s32k144基于CANoe的UDS诊断数据库CDD文件及CAPL Boot上位机、下位机程序移植说明文档.pdf
STM32系列通信透传技术:以太网、串口、CAN透传及OBD协议解析.pdf
STM32开发:IIR带阻滤波器设计与实现.pdf
UG后处理:CNC西门子828D后处理与西门子后处理工厂实战自用.pdf
MYSQL深入学习总结.pdf
Stewart六自由度平台反解算法 C#.pdf
1、文件说明: Centos8操作系统vim-ale-3.3.0-1.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf vim-ale-3.3.0-1.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm
tc275、s12x和s32k144的Boot程序及UDS故障诊断与Bootloader移植的Python自制上位机源码.pdf
SSA-CNN-LSTM时间序列预测(Matlab)_ 麻雀算法优化卷积长短期记忆网络.pdf
UI篇:C#工控上位机Chart控件实现与展示.pdf
SRM12-8开关磁阻电机,功率2200w,额定转速3450rpm.pdf