使用synchronized 的一些限制:
1、无法中断正在等候获取一个锁的线程;
来源:http://blog.csdn.net/quqi99/article/details/5298017
- package test;
- public interface IBuffer {
- public void write();
- public void read() throws InterruptedException;
- }
使用Synchronized:
- package test;
- public class Buffer implements IBuffer {
- private Object lock;
- public Buffer() {
- lock = this;
- }
- public void write() {
- synchronized (lock) {
- long startTime = System.currentTimeMillis();
- System.out.println("开始往这个buff写入数据…");
- for (;;)// 模拟要处理很长时间
- {
- if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
- break;
- }
- System.out.println("终于写完了");
- }
- }
- public void read() {
- synchronized (lock) {
- System.out.println("从这个buff读数据");
- }
- }
- }
使用ReentrantLock:
- package test;
- import java.util.concurrent.locks.ReentrantLock;
- public class BufferInterruptibly implements IBuffer {
- private ReentrantLock lock = new ReentrantLock();
- public void write() {
- lock.lock();
- try {
- long startTime = System.currentTimeMillis();
- System.out.println("开始往这个buff写入数据…");
- for (;;)// 模拟要处理很长时间
- {
- if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
- break;
- }
- System.out.println("终于写完了");
- } finally {
- lock.unlock();
- }
- }
- public void read() throws InterruptedException{
- lock.lockInterruptibly();// 注意这里,可以响应中断
- try {
- System.out.println("从这个buff读数据");
- } finally {
- lock.unlock();
- }
- }
- }
测试类(注意那两个线程不是内部类!):
- package test;
- public class Test {
- //是用ReentrantLock,还是用synchronized
- public static boolean useSynchronized = false;
- public static void main(String[] args) {
- IBuffer buff = null;
- if(useSynchronized){
- buff = new Buffer();
- }else{
- buff = new BufferInterruptibly();
- }
- final Writer writer = new Writer(buff);
- final Reader reader = new Reader(buff);
- writer.start();
- reader.start();
- new Thread(new Runnable() {
- public void run() {
- long start = System.currentTimeMillis();
- for (;;) {
- // 等5秒钟去中断读
- if (System.currentTimeMillis() - start > 5000) {
- System.out.println("不等了,尝试中断");
- reader.interrupt();
- break;
- }
- }
- }
- }).start();
- }
- }
- class Writer extends Thread {
- private IBuffer buff;
- public Writer(IBuffer buff) {
- this.buff = buff;
- }
- @Override
- public void run() {
- buff.write();
- }
- }
- class Reader extends Thread {
- private IBuffer buff;
- public Reader(IBuffer buff) {
- this.buff = buff;
- }
- @Override
- public void run() {
- try {
- buff.read();
- } catch (InterruptedException e) {
- System.out.println("我不读了");
- }
- System.out.println("读结束");
- }
- }
结果:
使用ReentrantLock时:
开始往这个buff写入数据…
不等了,尝试中断
我不读了
读结束
使用Synchronized时:
开始往这个buff写入数据…
不等了,尝试中断
2、无法通过投票得到一个锁;
3、释放锁的操作只能与获得锁所在的代码块中进行,无法在别的代码块中释放锁;ReentrantLock 没有以上的这些限制,且必须是手工释放锁。
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,当许多线程都在争用同一个锁时,使用 ReentrantLock 的总体开支通常要比 synchronized 少得多。
synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
(1)用法区别
synchronized(隐式锁):在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。
lock(显示锁):需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对 象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。
(2)synchronized和lock性能区别
synchronized是托管给JVM执行的,而lock是java写的控制锁的代码。
synchronized采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味着其 他线程只能依靠阻塞来等待线程释放锁。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低。
Lock用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就 是CAS操作(Compare and Swap)。
(3)synchronized和lock用途区别
synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候、
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length)
putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}</p><p> public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length)
takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
原文:
https://yq.aliyun.com/articles/38340