首页 > 其他 > 详细

synchronized 保证三大特性

时间:2020-06-24 11:44:00      阅读:155      评论:0      收藏:0      [点我收藏+]

synchronized 能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果;

synchronized(锁对象) {
    // 受保护资源;
}

synchronized 与原子性

  目标:学习使用 synchronized 保证原子性的原理

使用 synchronized 保证原子性

  案例:5个线程各执行10000次 i++

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

synchronized 保证原子性的原理

对 number++;增加同步代码快,保证同一时间只有一个线程操作 number++;。就不会出现安全问题;


synchronized 与可见性

目标:学习使用 synchronized 保证可见性的原理

使用 synchronized 保证可见性

  案例演示:一个线程根据 boolean 类型标记 flag,while循环,另一个线程改变这个flag变量的值,另一个线程不会停止循环

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

小结:

synchronized 保证可见性的原理,执行 synchronized时,会对应执行 lock 原子操作会刷新工作内存中共享变量的值;


synchronized 与有序性

  目标:学习使用 synchronized 保证有序性的原理

为什么要重排序

  为了提高程序的执行效率,编译器和CPU对象程序中的代码进行重排序;

as-if-serial语义

  as-if-serial语义的意思是:不管编译器和CPU如何重排序,必须保证单线程情况下程序的结果是正确的;

以下数据有依赖关系,不能重排序

写后读

int a = 1;
int b = a;

写后写

int a =  1;
int b = a;

读后写

int a = 1;
int b = a;
int a = 2;

编译器和处理器不会存在数据依赖关系的操作做重排序,因为这种排序会改变执行结果。但是,如果操作之间不存在依赖关系,这些操作就可能被编译器和处理器重排序;

int a = 1;
int b = 2;
int c = a + b;

上面 3 个操作的数据依赖关系如图所示:

技术分享图片

如图所示 a 和 c 之间存在数据依赖关系,同时 b 和 c 之间也存在数据依赖关系。因此在最终执行的指令序列中,c 不能被重排序到 a 和 b 的前面。但是 a 和 b 之间没有数据依赖关系,编译器和处理器可以重排序 a 和 b 之间的执行顺序;下图是该程序的两种执行顺序;

技术分享图片

使用 synchronized 保证有序性

synchronized 保证三大特性

原文:https://www.cnblogs.com/lililixuefei/p/13186068.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!