Synchornized、Volatile及Semaphore之间的区别

目录

一、Synchornized

(一) synchornized分为对象锁和类锁两大类

对象锁

类锁

(二)、synchornized生产者--消费者模型:

wait和sleep的区别:

wait跟notify区别:

注意:

二、Volatile

 Volatile的特点:

Volatile和synchornized的区别:

三、Semaphore

一、Synchornized

(一) synchornized分为对象锁和类锁两大类


对象锁


1.方法锁:默认使用this作为锁对象,该方法为普通方法 public synchornized void a() {} 
2.同步代码块锁:必须显示提供锁对象,可自定义锁对象 synchornized(Object 0 ){}


类锁


1.使用*.class作为锁对象  synchornized(.*class){}
2.synchornized修饰静态方法 public static synchornized void a() {}

注意:

如果一个线程A调用一个实例对象的非static synchornized方法,而线程B需要调用这个实例对象所属类的静态synchornized方法,是允许的,不会发生互斥现象,因为访问静态synchornized方法占用的是当前类的class对象,而访问非静态synchornized方法占用的锁是当前实例对象锁,两者不一致。

**它的核心是:** 锁对象是否一致

注意:
1.Object.class只有一个,不论new多少个对象,都会互斥
2.this 如果是在某个类里面,如果创建多个这个类,则不互斥

例如下面示例:
```java
class C {
    fun1() {
        synchornized(this) {
            
        }
    }
    fun2() {
        synchornized(this) {
            
        }
    }
}
C c1 = new C();
C c2 = new C();
```

(二)、synchornized生产者--消费者模型:

生产者的主要作用是生成一定量的数据放到缓冲区,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者不会在缓冲区空时消耗数据。

wait和sleep的区别:


sleep:睡眠,占用资源
wait:释放资源(锁,cpu),立刻释放

wait跟notify区别:


notify:不是立刻释放锁,等到代码块执行完后释放锁,而wait会立刻释放

notifyAll写在代码块前还是后都没有区别

注意:


 - 当生产者遇到仓库满时,生产者线程被挂起。当消费者遇到仓库空时,消费者线程被挂起。
 - 我们需要在wait()方法上加一层条件循环判断,如果不满足,执行wait(),继续被挂起。如果满足,跳出循环。
 - wait跟notify来自 根类Object
 - 当线程进入同步方法并运行结束后,使用notifyAll() 解除所有线程的阻塞。
 - notify唤醒线程,这个线程有可能不是我们想要的线程,最好使用notifyAll()进行唤醒。

二、Volatile


博客链接:https://blog.csdn.net/m0_63039919/article/details/129223883?ops_request_misc=&request_id=&biz_id=102&utm_term=synchornized&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~sobaiduweb~default-3-129223883.nonecase&spm=1018.2226.3001.4450

原因: 为了保证线程地稳定性

执行业务逻辑时,线程会把主内存中的变量copy到线程的工作内存(寄存器跟高速缓存),后续发生的读写操作都是对工作内存中的副本变量进行的。如果频繁地读取内存,频繁地从内存上读到”工作内存“上的数据都相同的话,那么CPU为了优化速率,可能就不会每次都从内存开始读起,而是直接在“工作内存”上读取。因为直接读寄存器会比读内存要快很多。但是这样就容易导致如果其他线程改了内存上的数据,该线程不能及时知道,还在读寄存器或高速缓冲区。

精确的说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

 Volatile的特点:

 volatile保证了可见性
- volatile保证了单线程下指令不重排:通过插入内存屏障保证指令执行顺序。
- volatile不保证原子性,如a++这种自增操作是有并发风险的,比如扣减库存、发放优惠券的场景。
- volatile类型的64位的long型和double型变量,对该变量的读/写具有原子性。
- volatile 可以用在双重验证的单例模式中,比synchornized性能更好。
- volatile可以用在检查某个状态标记以判断是否退出循环。

Volatile和synchornized的区别:

- volatile只能修饰 实例变量 和 类变量, synchornized 可以修饰方法 和 代码块。
- volatile 不保证 原子性,而 synchornized 保证原子性。
- volatile 不会造成阻塞发,而synchornized 可能会造成阻塞
- volatile 轻量级锁,synchornized 重量级锁
- volatile 和 synchornized 都保证了可见性 和 有序性。

三、Semaphore

Semaphore是一个用于控制并发访问资源的机制。它可以用来限制同时访问某个资源的线程数量。Semaphore维护一个计数器,线程在访问资源之前需要先获取信号量,如果计数器大于0,则允许访问资源并将计数器减1;如果计数器等于0,则线程需要等待其他线程释放信号量。

public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}

第二个构造函数可以指定是为公平模式还是非公平模式,默认不公平模式。
主要有两个方法,一个是获得许可 acquire 另一个是释放许可release
require方法中其实最终都会执行acquireSharedInterruptibly;如果线程中断则终止,采集失败则阻塞获取锁。

public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}


 

  • 22
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不想迷路的小男孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值