java 关键字 volatile、synchronized、Lock

本文详细介绍了Java并发编程中的volatile关键字、synchronized同步锁以及Lock接口。volatile提供可见性和有序性,但不保证原子性。synchronized用于修饰代码块和方法,确保同一时刻只有一个线程执行,而Lock提供了更细粒度的锁控制,包括可中断的锁获取、尝试获取锁等。在资源竞争不激烈的情况下,synchronized性能较好,但在竞争激烈时,Lock可能更优。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

volatile:

简介:
    用以声明变量的值可能随时会别的线程修改
    使用volatile修饰的变量会强制将修改的值立即写入主存
    主存中值的更新会使缓存中的值失效
    
特性:
    1. 可见性
        当多个线程访问同一个变量时,某一个线程修改了变量的值,其他线程能够立即读取到该变量修改后的值。
    2. 有序性
        即程序执行时按照代码书写的先后顺序执行。
        在Java内存模型中,允许编译器和处理器对指令进行重排序,
        但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
    3. 不具有原子性
        原子性:
            即事务执行不完全会发生事务回滚,恢复初始状态。

注意:
    volatile不会让线程阻塞,响应速度比synchronized高,这是它的优点。
    

synchronized 同步锁

功能:
    1. 修饰代码块:
        被修饰的代码块称为同步语句块,
        其作用的范围是大括号{}括起来的代码,
        作用的对象是调用这个代码块的对象
        一个线程访问一个对象中的synchronized(this)同步代码块时,
        其他试图访问该对象的线程将被阻塞。
        说明:
            当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,
            在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。
            Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的对象,
            只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。
            每通过new关键字创建一个对象都是不同的对象,不能称作同一对象。
            
    2. 修饰方:
        被修饰的方法称为同步方法,
        其作用的范围是整个方法,
        作用的对象是调用这个方法的对象
        当一个线程访问对象的一个synchronized(this)同步代码块时,
        另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。
        说明:
            countAdd是一个synchronized的,printCount是非synchronized的。
            一个线程访问一个对象的synchronized代码块时,别的线程可以访问该对象的非synchronized代码块而不受阻塞。
        
    3. 修饰静态的方法:
        其作用的范围是整个静态方法,
        作用的对象是这个类的所有对象
        synchronized修饰方法和修饰一个代码块类似,只是作用范围不一样,
        修饰代码块是大括号括起来的范围,而修饰方法范围是整个函数。
        静态方法是属于类的而不属于对象的。
        synchronized修饰的静态方法锁定的是这个类的所有对象。
        说明:
            两种写法:
                1. public synchronized void method () {}
                2. public void method () {
                        synchronized (this) {}
                    }
        注意:
            1. synchronized关键字不能继承。
            2. 在定义接口方法时不能使用synchronized关键字。
            3. 构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步
            
        
    4. 修饰类:
        其作用的范围是synchronized后面括号括起来的部分,
        作用主的对象是这个类的所有对象
        synchronized作用于一个类T时,
        是给这个类T加锁,T的所有对象用的是同一把锁。


Lock

1. 通过Lock可以知道线程有没有成功获取到锁。synchronized无法办到的。

2. Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。
    Lock是一个类,通过这个类可以实现同步访问

3. synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,
    而且在代码执行时出现异常,JVM会自动释放锁定,
    但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中

4. 在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,
    但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,
    
lock的四个取锁方法:
    lock()
        就是用来获取锁。如果锁已被其他线程获取,则进行等待。
    tryLock()
        有返回值,表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,
        也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
    tryLock(long time, TimeUnit unit)
        这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。
        如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
    lockInterruptibly()
        在获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。
        也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,
        假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。
    
注意:
    使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,
    以保证锁一定被释放,防止死锁的发生。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值