几个并发编程的例子
在这里讨论一下自己遇到的几个自己感觉比较好的并发编程的例子。如果读者已经完全明白是怎么回事,请略过。
例一:
先看如下程序,想一下这个程序多长时间结束?
- 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();
- }
- }
- }
相关推荐
│ 高并发编程第二阶段05讲、一个解释volatile关键字作用最好的例子.mp4 │ 高并发编程第二阶段06讲、Java内存模型以及CPU缓存不一致问题的引入.mp4 │ 高并发编程第二阶段07讲、CPU以及CPU缓存的结构,解决高速...
│ 高并发编程第二阶段05讲、一个解释volatile关键字作用最好的例子.mp4 │ 高并发编程第二阶段06讲、Java内存模型以及CPU缓存不一致问题的引入.mp4 │ 高并发编程第二阶段07讲、CPU以及CPU缓存的结构,解决高速...
Java并发编程的艺术_非扫描本书特色本书结合JDK的源码介绍了Java并发框架、线程池的实现原理,帮助读者做到知其所以然。本书对原理的剖析不仅仅局限...第11章介绍几个并发编程的实战,以及排查并发编程造成问题的方法。
写在前面 并发编程一直都存在,只不过过去的很长时间里,比较...关于并发编程的几个误解 误解一:并发编程就是多线程 实际上多线只是并发编程的一中形式,在C#中还有很多更实用、更方便的并发编程技术,包括异步编
并发编程 这个系列,我准备了将近一个星期,从知识点梳理,到思考要举哪些例子才能更加让人容易吃透这些知识点。希望呈现出来的效果真能如想象中的那样,对小白也一样的友好。 昨天大致整理了下,这个系列我大概会...
一、Synchronized的基本使用 ... 接下来我通过几个例子程序来说明一下这三种使用方式(为了便于比较,三段代码除了Synchronized的使用方式不同以外,其他基本保持一致)。 1、没有同步的情况: 代码段一: 1 p
多线程编程是一个很有意思也很有用的技术,使用多线程技术的网络蚂蚁是目前最常用的下载工具之一,使用多线程技术的grep比单线程的grep要快上几倍,类似的例子还有很多。希望大家能用多线程技术写出高效实用的好程序...
6.1 几个关键概念 199 6.2 自定义类型 201 6.2.1 添加方法 203 6.2.2 验证类型 207 6.3 接口 209 6.4 结构体 217 6.5 例子 224 6.5.1 FuzzyBool——一个单值自定义类型 224 6.5.2 Shapes——一系列...
深入理解计算机系统 中文 第二版 共2部分,这个是part2 内容简介 · · · · · · 本书从程序员的视角详细阐述计算机系统的本质概念,并展示这些概念如何实实在在地影响应用程序的正确性、性能和实用性。全书...
Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run Anywhere): Java的代码可以在不同的平台上运行,只需编写一次代码,就可以在任何支持Java的设备上执行。这得益于Java虚拟机(JVM),它充当了...
2.3 一个多核处理器架构例子 ............................................................................................................... 5 2.4 LINUX 线程核绑定 .........................................
6.1 几个关键概念 199 6.2 自定义类型 201 6.2.1 添加方法 203 6.2.2 验证类型 207 6.3 接口 209 6.4 结构体 217 6.5 例子 224 6.5.1 FuzzyBool——一个单值自定义类型 224 6.5.2 Shapes——一系列...
本书给出了能说明每个设计思想的实现方法,讨论了包括应用层网关和管道在内的各种技术,回顾了几个标准应用协议,并使用它们说明一些算法和实现技术。本书包含的一些例子程序显示了每个设计实际上如何操作,大多数的...
Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run Anywhere): Java的代码可以在不同的平台上运行,只需编写一次代码,就可以在任何支持Java的设备上执行。这得益于Java虚拟机(JVM),它充当了...
中文第二版,共2部分,这个是part1 内容简介 · · · · · · 本书从程序员的视角详细阐述计算机系统的本质概念,并展示这些概念如何实实在在地影响应用程序的正确性、性能和实用性。全书共12章,主要内容包括...
2.3.1 一个多文件的工程例子............................. ............. 34 2 . 3 . 2多文件工程的编译.............................................. 36 2.3.3 Makefile 的规则..................................
【练习】:循环创建多个线程,每个线程打印自己是第几个被创建的线程。(类似于进程循环创建子进程) 【more_pthrd.c】 拓展思考:将pthread_create函数参4修改为(void *)&i, 将线程主函数内改...
本节介绍如何编写 Spark Streaming 应用程序,由简到难讲解使用几个核心概念来解决实际应用问题。 流数据模拟器 在实例演示中模拟实际情况,需要源源不断地接入流数据,为了在演示过程中更接近真实环境,首先需要...