首页 java实战 synchronized和Lock主要区别

synchronized和Lock主要区别

最大的区别 synchronized:在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特…

最大的区别

synchronized:在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。

synchronized会的ReentrantLock都能搞定

lock:需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。

synchronized的介绍

下面列举下用法

执行结果

synchronized可以用在方法上和代码块上

synchronized 用在方法签名上(以showA为例),当某个线程调用此方法时,会获取该实例的对象锁,方法未结束之前,其他线程只能去等待。当这个方法执行完时,才会释放对象锁。(以showB为例)其他线程才有机会去抢占这把锁,去执行方法showB,但是发生这一切的基础应当是所有线程使用的同一个对象实例,才能实现互斥的现象。否则synchronized关键字将失去意义。

但是如果该方法为类方法,即其修饰符为static,那么synchronized 意味着某个调用此方法的线程当前会拥有该类的锁,只要该线程持续在当前方法内运行,其他线程依然无法获得方法的使用权!

synchronized注意点

1、可以只对需要同步的使用

2、与wait()/notify()/nitifyAll()一起使用时,比较方便

这里补充下一些其他知识

wait() 与notify()/notifyAll()

这三个方法都是Object的方法,并不是线程的方法!

wait():释放占有的对象锁,线程进入等待池,释放cpu,而其他正在等待的线程即可抢占此锁,获得锁的线程即可运行程序。而sleep()不同的是,线程调用此方法后,会休眠一段时间,休眠期间,会暂时释放cpu,但并不释放对象锁。也就是说,在休眠期间,其他线程依然无法进入此代码内部。休眠结束,线程重新获得cpu,执行代码。wait()和sleep()最大的不同在于wait()会释放对象锁,而sleep()不会!

notify(): 该方法会唤醒因为调用对象的wait()而等待的线程,其实就是对对象锁的唤醒,从而使得wait()的线程可以有机会获取对象锁。调用notify()后,并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,才会释放对象锁。JVM则会在等待的线程中调度一个线程去获得对象锁,执行代码。需要注意的是,wait()和notify()必须在synchronized代码块中调用

notifyAll()则是唤醒所有等待的线程。

ReentrantLock 与synchronized有相同的并发性和内存语义,还包含了中断锁等候和定时锁等候,意味着线程A如果先获得了对象obj的锁,那么线程B可以在等待指定时间内依然无法获取锁,那么就会自动放弃该锁

但是由于synchronized是在JVM层面实现的,因此系统可以监控锁的释放与否,而ReentrantLock使用代码实现的,系统无法自动释放锁,需要在代码中finally子句中显式释放锁lock.unlock();

ReentrantLock介绍

ReentrantLock可以与Condition的配合使用,Condition为ReentrantLock锁的等待和释放提供控制逻辑。

  1. ReentrantLock功能性方面更全面,比如时间锁等候,可中断锁等候,锁投票等,因此更有扩展性。在多个条件变量和高度竞争锁的地方,用ReentrantLock更合适,ReentrantLock还提供了Condition,对线程的等待和唤醒等操作更加灵活,一个ReentrantLock可以有多个Condition实例,所以更有扩展性。
  2. ReentrantLock必须在finally中释放锁,否则后果很严重,编码角度来说使用synchronized更加简单,不容易遗漏或者出错。
  3. ReentrantLock 的性能比synchronized会好点。
  4. ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以更容易产生死锁。

使用技巧

final ReentrantLock spillLock = new ReentrantLock();

final Condition spillDone = spillLock.newCondition();

spillLock.lock(); 锁

spillDone.await(); 等待进程

spillDone.signal(); 唤醒

spillLock.unlock(); 解锁

代码中spillDone 就是 spillLock的一个newCondition()。调用spillDone.await()时可以释放spillLock锁,线程进入阻塞状态,而等待其他线程的 spillDone.signal()操作时,就会唤醒线程,重新持有spillLock锁。

使用建议:

在并发量比较小的情况下,使用synchronized是个不错的选择,但是在并发量比较高的情况下,其性能下降很严重,此时ReentrantLock是个不错的方案。

免责声明:文章内容不代表本站立场,本站不对其内容的真实性、完整性、准确性给予任何担保、暗示和承诺,仅供读者参考,文章版权归原作者所有。如本文内容影响到您的合法权益(内容、图片等),请及时联系本站,我们会及时删除处理。

为您推荐

mysql 统计日期 今天,昨天,上个月,这个月 ,一年

mysql 统计日期 今天,昨天,上个月,这个月 ,一年

查询5分钟前的数据 select * from table where end_date between date_ad...
Illegal key size or default parameters

Illegal key size or default parameters

简介: java中使用AES对称加密后,请求报错: Caused by: java.lang.RuntimeExcept...
nginx跨域问题

nginx跨域问题

add_header Access-Control-Allow-Origin *; add_header Access-...
Ajax请求发送成功但不进success的解决方法

Ajax请求发送成功但不进success的解决方法

dataType:’Text’ 格式严格按照服务端返回的数据来
【java】post请求参数全大写后台接不到参数

【java】post请求参数全大写后台接不到参数

测试验证的时候发现,接收不到请求参数   驼峰正常 springMVC使用的是Jackson来解析json格式的请求报文...
返回顶部