您的位置:首页 > 其它

ReentrantLock和synchronized比较

2016-08-09 16:33 381 查看
(1)什么情况下可以使用 ReentrantLock
使用synchronized 的一些限制: 
1、无法中断正在等候获取一个锁的线程;

来源:http://blog.csdn.net/quqi99/article/details/5298017

Java代码  


package test;  

  

public interface IBuffer {  

    public void write();  

    public void read() throws InterruptedException;  

}  

使用Synchronized:

Java代码  


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:

Java代码  


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();  

        }  

    }  

  

}  

  

测试类(注意那两个线程不是内部类!):

Java代码  


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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: