synchronized概述

各位好久不见,今天我将会把synchronized 关键字的相关知识点进行总结学习,还需要把之前已经总结过的知识点再巩固学习。

synchronized 关键字

作用是保证一个时刻点上只有一个线程在执行,不会出现并发的情况,达到排队执行的目的。

用法:

对象锁、类锁和同步块。注意:synchronized 不能修改构造器、变量等,synchronized 支持重入

synchronized 特性

原子性:确保线程互斥的访问同步代码。synchronized保证只有一个线程拿到锁,进入同步代码块操作共享资源,因此具有原子性。

可见性:保证共享变量的修改能够及时可见。执行 synchronized时,会对应执行 lock 、unlock原子操作。lock操作,就会清空工作空间该变量的值;执行unlock操作之前,必须先把变量同步回主内存中。

有序性:synchronized内的代码和外部的代码禁止排序,至于内部的代码,则不会禁止排序,但是由于只有一个线程进入同步代码块,因此在同步代码块中相当于是单线程的,根据 as-if-serial 语义,即使代码块内发生了重排序,也不会影响程序执行的结果。

悲观锁:synchronized是悲观锁。每次使用共享资源时都认为会和其他线程产生竞争,所以每次使用共享资源都会上锁。

独占锁(排他锁):synchronized是独占锁(排他锁)。该锁一次只能被一个线程所持有,其他线程被阻塞。

非公平锁:synchronized是非公平锁。线程获取锁的顺序可以不按照线程的阻塞顺序。允许线程发出请求后立即尝试获取锁。

可重入锁:synchronized是可重入锁。持锁线程可以再次获取自己的内部的锁。

同步实例方法:

修饰实例方法,作用域当前实例加锁,进入同步方法需要获取当前实例的锁。 方法上添加 synchronized 关键字,例如 public synchronized void show() 。

1、只要有一个线程进入了当前类对象的同步方法,则不允许其它线程再次进入当前对象的任何同步方法,但是允许进入非同步方法

2、同样当前线程可以进入当前类对象的其它同步方法(重入),也允许进入非同步方法。当线程进入同步方法,则获取同步锁,离开同步方法则自动释放锁

3、这个锁就是当前类对象

public class Account{
    private Long id;
    private Double balance;
    public synchronized void withdraw(double number){
        //...
    }
    public synchronized void disposit(double number){
        //...
    }
}

同步静态方法:

修改静态方法,作用于当前类对象加锁,进入同步静态方法需要获取当前类对象的锁。

public class NumOper { 
    private static int num=0; 
    public static synchronized void add(){ 
        int cc=num;//缓存数据 
        try { 
            Thread.sleep(100); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        }
        cc++; 
        num=cc; 
        System.out.println("数据:"+cc); 
    }
    public static void main(String[] args) { 
        Thread[] ts=new Thread[10]; 
        for(int i=0;i<ts.length;i++){ 
            ts[i]=new Thread(()->{ //构建 10 个 NumOper 对象,如果使用实例同步方法,则不能达到锁定的目的 
                NumOper no=new NumOper(); 
                no.add(); 
            });
            ts[i].start(); 
        }
        for(Thread t:ts) 
            try {
                t.join(); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        System.out.println(NumOper.num); 
    }
}

同步代码块:

使用 synchronized 修饰代码块时同时指定加锁对象,对给定对象加锁,进入同步代码块的前提时获取指定对象的锁。建议在可能被并发访问的 goon 共享临界资源使用,通过这种方法可以保证并发线程在任何一个时刻只有线程可以进入修改共享的临界资源的代码块(临界区)。

public class App { 
    private static int num=0; 
    private Object lock;//充当锁的对象 
    public App(Object lock){ 
        this.lock=lock; 
    }
    public void add(){ 
        synchronized (lock) { //同步代码块,可以是方法种的一部分代码,也可以是方法种的所有 代码,这里没有严格要求,synchronized 种的代码要求同步处理,不包含在 synchronized 种的方法不需 要同步处理。限制的颗粒都明显比方法还小 
            int cc=num; 
            try { 
                Thread.sleep(100); 
            } catch (InterruptedException e) {
                 e.printStackTrace(); 
            }
            cc++; 
            num=cc; 
            System.out.println(cc); 
        }
    } 
}

好了,今天的知识点就先总结学习到这里吧,欢迎各位大神提出意见。

### Java `synchronized` 关键字工作原理 #### 机制概述 `synchronized` 是 Java 中用于控制多个线程对共享资源访问的关键字。它通过提供一种内置的方式,确保同一时刻只有一个线程能够执行被保护的代码段[^1]。 #### 使用场景与方式 `synchronized` 主要应用于以下三种情况: - **实例方法**:当声明为 `synchronized` 的实例方法被调用时,该对象上的所有其他 `synchronized` 方法都将等待当前方法完成。 - **静态方法**:如果标记的是静态方法,则定整个类级别的,即 Class 对象,在这种情况下,所有的此类实例都会受到影响。 - **代码块**:可以指定特定的对象作为参数,从而更灵活地定义加范围,适用于细粒度控制的情况。 ```java public class SyncExample { private final Object lock = new Object(); public void methodA() { synchronized (lock) { // 显式指定对象 // 只有一个线程能进入此区域 } } public synchronized void instanceMethod() { // 实例方法默认使用 this 作为 } public static synchronized void staticMethod() { // 静态方法使用 .class 文件对应的 Class 对象作为 } } ``` #### 底层实现细节 在 JVM 层面,每当遇到 `monitorenter` 和 `monitorexit` 字节码指令时就会触发的操作。对于未竞争的状态下,JVM 尽量减少不必要的重量级同步开销;而对于存在多线程争夺同一个的情形,则会逐步升级状态以提高性能效率[^2]。 完整的升级路径如下: 1. 偏向(Biased Locking) 2. 轻量级(Lightweight Locking) 3. 重量级(Heavyweight Locking) 每一步骤都是为了适应不同的并发程度而设计的不同层次的优化措施[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值