高并发之Synchronized(超详细笔记)

本文详细探讨了Java中的Synchronized关键字,包括其作用、地位、两种用法(对象锁和类锁)、多线程访问同步方法的场景、性质、原理以及面试常见问题。总结了Synchronized的三大核心思想:互斥、可重入性和可见性,并讨论了其与Lock接口的区别。文章还提出了思考题,涉及JVM选择下一个获取锁线程的方式以及性能优化策略。
摘要由CSDN通过智能技术生成

高并发之Synchronized

原文链接:高并发之Synchronized

Synchronized简介

Synchronized的作用

官方解释

Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors:if an object is visible to more than one thread,all reads or writes to that object’s variables are done through synchronized methods.

一句话说出Synchronized的作用

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

Synchronized的地位

  • Synchronized是Java的一个关键字
  • 是最基本的互斥同步的手段
  • 是并发编程中的元老级角色,是并发编程的必学内容

不用并发手段的后果

代码实战:两个线程同事a++,最后结果会比预期少

/**
 * @program: concurrency_demo
 * @Author: RONGHUA.YU@HAND-CHINA.COM
 * @Date: 2019/9/17 15:14
 * @Description: 高并发之消失的请求,两个线程对i++,执行100000次,结果一定小于200000
 */
public class DisappearRequest1 implements Runnable{
   

    static DisappearRequest1 disappearRequest1 = new DisappearRequest1();
    static int i = 0;
    public static void main(String[] args) throws InterruptedException {
   

        Thread t1 = new Thread(disappearRequest1);
        Thread t2 = new Thread(disappearRequest1);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }

    @Override
    public void run() {
   

        for (int j = 0; j < 100000; j++) {
   
            i++;
        }
    }
}

运行结果:

132889

原因:
count++,它看上去只是一个操作,实际上包含了三个动作:

  1. 读取count
  2. 将count加一
  3. 将count的值写道内存中
    这三个动作执行到任何一个动作时,都有可能被打断,如此时count为9,线程a执行到+1操作,count的值变为10.但是还没来得及写入内存,线程b就开始执行,此时读取到的count依然是9,这和我们的预期就不同了,我们称之为线程不安全

Synchronized的两种用法

Synchronized的两种用法介绍

对象锁,包括方法锁(默认锁对象为this当前实例对象)和同步代码块锁(自己指定锁对象)

类锁,指synchronized修饰静态的方法或指定锁为Class对象

第一个用法:对象锁

代码块锁

代码块形式:手动指定锁对象

锁对象的选取:若不特定锁对象,可以用this(当前对象)作为我们的锁。

但有时候情况比较复杂,需要我们自己去选取锁对象,比如我们有多个个synchronized代码块,不是它们其中一个执行其它的就不能执行,而是可以同步执行,如下例,定义了两个Object类型的对象作为我们的锁,此时代码运行就可以是两两配对地运行。

/**
 * @program: concurrency_demo
 * @Author: RONGHUA.YU@HAND-CHINA.COM
 * @Date: 2019/9/12 14:08
 * @Description: 对象锁示例一:代码块锁
 */
public class SynchronizedObjectCodeBlock2 implements Runnable {
   
    static SynchronizedObjectCodeBlock2 instance = new SynchronizedObjectCodeBlock2();

    final Object lock1 = new Object();
    final Object lock2 = new Object();

    @Override
    public void run() {
   
        //代码块形式
        synchronized (lock1) {
   
            System.out.println("我是lock1。我叫" + Thread.currentThread().getName());
            try {
   
                Thread.sleep(3000);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "lock1运行结束");
        }

        synchronized (lock2) {
   
            System.out.println("我是lock2。我叫" + Thread.currentThread().getName());
            try {
   
                Thread.sleep(3000);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "lock2运行结束");
        }
    }

    public static void main(String[] args) {
   
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while(t1.isAlive()||t2.isAlive()){
   

        }
        System.out.println("finished");
    }
}

运行结果:

我是lock1。我叫Thread-0
Thread-0lock1运行结束
我是lock2。我叫Thread-0
我是lock1。我叫Thread-1
Thread-1lock1运行结束
Thread-0lock2运行结束
我是lock2。我叫Thread-1
Thread-1lock2运行结束
finished

除了这种情况,可能还有更复杂的情形,比如三个线程等待一个线程,再比如线程之间还有通信,就很难处理了,可能通过我们自己的努力也是能写出来,但是不建议自己写,因为如果稍有疏忽,就可能出现比较大的错误,那怎么去避免?实际上jdk为我们提交了几个非常完善的同步控制工具类,例如CountDownLatch、CyclicBarrier、Semaphore、Exchanger等等,有兴趣的可以去了解。

方法锁形式

synchronized修饰普通方法(非静态方法),锁对象默认为this

/**
 * @program: concurrency_demo
 * @Author: RONGHUA.YU@HAND-CHINA.COM
 * @Date: 2019/9/12 14:08
 * @Description: 对象锁示例二:方法锁
 */
public class SynchronizedObjectMethod3 implements Runnable {
   
    static SynchronizedObjectMethod3 instance = new SynchronizedObjectMethod3();

    @Override
    public void run() {
   
        method();
    }

    private synchronized void method() {
   

        System.out.println("我是对象锁的方法修饰符形式,我叫" + Thread.currentThread().getName());
        try {
   
            Thread.sleep(3000);
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "运行结束");

    }

    public static void main(String[] args) {
   
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值