并发编程基础 - synchronized使用场景和等待唤醒机制的正确姿势

it2026-10-05  2

    在理解完synchronized关键字反汇编之后信息,基于内存屏障解决了可见性和有序性,再基于MESA管程模型解决了线程的互斥和同步,并且顺便将执行的过程封装起来,中间状态对外不可见,解决了原子性。重点是理解管程模型是理解synchronized使用的关键,也理解了其模型,如图:

1、synchronized使用场景

1)、普通方法(锁的的对象,当同一个对象的多个synchronized方法才互斥)

    该使用场景比较多,比如SringBuffer的几乎所以方法:

2)、静态方法(锁的是Class文件,所以对象的所有synchronized方法互斥)

在自己的项目中没有使用过,但是发现java偏底层的代码用的会多一些,如下:

 

3)、代码块

    代码块则需要显示的在括号内加锁需要锁住的资源,当然其实也可以锁住对象this,或者 AAA.class。静态代码块其实与方法上的修饰类似,因为所有的静态代码块都可以抽成方法再加synchronized关键字。

    但是一般下synchronized修饰方法块的话,是类似上图专门见一个 Object类型的对象进行加锁,第一次见这种写法还是在Spring的源码中(使用非常多),后面才知道这算是一种标准的写法。比如 Spring AbstractApplicationContext 中与Spring(IOC)容器生命周期相关的方法都使用了同一个Monitor监视器对象,代码大致如下:

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { /** Synchronization monitor for the "refresh" and "destroy". */ private final Object startupShutdownMonitor = new Object(); @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 省略refresh方法细节 } } @Override public void registerShutdownHook() { if (this.shutdownHook == null) { this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) { @Override public void run() { synchronized (startupShutdownMonitor) { doClose(); } } }; Runtime.getRuntime().addShutdownHook(this.shutdownHook); } } @Override public void close() { synchronized (this.startupShutdownMonitor) { doClose(); if (this.shutdownHook != null) { try { Runtime.getRuntime().removeShutdownHook(this.shutdownHook); } catch (IllegalStateException ex) { } } } } }

2、synchronized实现等待唤醒机制

    等待唤醒机制使用场景比较多,一个完整的等待唤醒机制过程:线程首先获取互斥锁,当线程要求的条件不满足时释放互斥锁,进入等待状态;当要求的条件满足时,通知等待的线程,重新获取互斥锁。直接在并发编程模式 - Guarded Suspension设计模式中使用ReentrantLock+Condition实现了一个版本,并且也分析了 Dubbo的异步请求Api的异步转同步的过程。Object的 wait、notify、notifyAll方法需要配合synchronized使用,即在其内部使用,并且写法基本固定。如果在synchronized外部调用 wait方法等,则会报 java.lang.IllegalMonitorStateException。

class Allocator { private List<Object> als; // 一次性申请所有资源 synchronized void apply( Object from, Object to){ // 经典写法 while(als.contains(from) || als.contains(to)){ try{ wait(); }catch(Exception e){ } } als.add(from); als.add(to); } // 归还资源 synchronized void free( Object from, Object to){ als.remove(from); als.remove(to); notifyAll(); } }

 

 

 

最新回复(0)