并发编程中的三个问题

Posted lililixuefei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程中的三个问题相关的知识,希望对你有一定的参考价值。

并发编程中的三个问题

可见性

  概念:可见性(Visibility)指一个线程对共享变量进行修改,另一个立即得到修改后的最新值;

package juc.synchronized_test;
?
import java.util.concurrent.TimeUnit;
?
/**
 * @author : 雪飞oubai
 * @date : 2020/4/9 11:07
 * 目的:演示可见性问题
 *      1、创建一个贡献变量
 *      2、创建一条线程不断的读取共享变量
 *      3、创建一条线程修改共享变量
 */
public class Test01Visibility {
    // 多个线程都会访问的数据,我们称为线程的共享数据
    private static boolean flag = true;
    public static void main(String[] args) throws InterruptedException {
       new Thread(() -> {
           while(flag){
?
           }
       }).start();
?
        TimeUnit.SECONDS.sleep(1);
?
        new Thread(() -> {
            flag = false;
            System.out.println("时间到,线程2设置为false");
        }).start();
    }
}

 


原子性

  概念:原子性(Atomicity)在一次或多次操作中,要么所有的操作都执行并且不会受其它因素影响,要么所有的操作都不执行;

package juc.synchronized_test;
?
import java.util.ArrayList;
import java.util.List;
?
/**
 * @author : 雪飞oubai
 * @date : 2020/4/9 11:27
 * 目标:演示原子性问题
 * 1、定义一个共享变量 number
 * 2、对number进行10000次 ++ 操作
 * 3、使用 5 个线程来进行
 */
public class Test02Atomicity {
    //1、定义一个共享变量 number
    private static int number = 0;
?
    public static void main(String[] args) throws InterruptedException {
        Runnable increment = () -> {
            for (int i = 0; i < 10000; i++) {
                number++;
            }
        };
        List<Thread> list = new ArrayList<>();
?
        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(increment);
            t.start();
            list.add(t);
        }
        for (Thread thread : list) {
            thread.join();
        }
        System.out.println("number="+number);
    }
}

 

其中,对于 number ++ 而言(number为静态变量),实际会产生如下的JVM字节码指令

技术图片

 

 

由此可见 number++ 是由多条语句组成,以上多条指令在一个线程的情况下不会出现问题,但是再多线程情况下就可能会出现问题。比如一个线程在执行 13:iadd时,另一个线程又执行 9:getstatic,会导致两次number++,实际上只会加一次;

小结

  并发编程会出现原子性问题,当一个线程对共享变量操作到一半时,另外的线程也有可能来操作共享变量,干扰了前一个线程的操作;

有序性

  概念:有序性(Ordering)是指程序中代码的执行顺序,Java在编译时和运行时会对代码进行优化,会导致程序最终的执行顺序不一定就是我们编写代码时的顺序;

 

以上是关于并发编程中的三个问题的主要内容,如果未能解决你的问题,请参考以下文章

[Java 并发编程实战] 设计线程安全的类的三个方式(含代码)

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

golang代码片段(摘抄)

《java并发编程实战》

以编程方式替换片段

ViewPager2:以编程方式选择特定片段