synchronized和ReentrantLock区别

2/13/2017来源:iOS开发人气:1049

sychronized

java中,每一个对象有且仅有一个同步锁。这也意味着,同步锁是依赖于对象而存在。 当我们调用某对象的synchronized方法时,就获取了该对象的同步锁。例如,synchronized(obj)就获取了“obj这个对象”的同步锁。 不同线程对同步锁的访问是互斥的。也就是说,某时间点,对象的同步锁只能被一个线程获取到!通过同步锁,我们就能在多线程中,实现对“对象/方法”的互斥访问。 例如,现在有两个线程A和线程B,它们都会访问“对象obj的同步锁”。假设,在某一时刻,线程A获取到“obj的同步锁”并在执行一些操作;而此时,线程B也企图获取“obj的同步锁” —— 线程B会获取失败,它必须等待,直到线程A释放了“该对象的同步锁”之后线程B才能获取到“obj的同步锁”从而才可以运行。

sychronized有三条原则: 1. 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。 2. 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。 3. 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

synchronized会在进入同步块的前后分别形成monitorenter和monitorexit字节码指令.在执行monitorenter指令时会尝试获取对象的锁,如果此没对象没有被锁,或者此对象已经被当前线程锁住,那么锁的计数器加一,每当monitorexit被锁的对象的计数器减一.直到为0就释放该对象的锁.由此synchronized是可重入的,不会出现自己把自己锁死.

ReentrantLock

ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”

顾名思义,ReentrantLock锁在同一个时间点只能被一个线程锁持有;而可重入的意思是,ReentrantLock锁,可以被单个线程多次获取。 ReentrantLock分为 公平锁非公平锁 。它们的区别体现在获取锁的机制上是否公平。 是为了保护竞争资源,防止多个线程同时操作线程而出错,ReentrantLock在同一个时间点只能被一个线程获取(当某线程获取到“锁”时,其它线程就必须等待);ReentraantLock是通过一个FIFO的等待队列来管理获取该锁所有线程的。在“公平锁”的机制下,线程依次排队获取锁;而“非公平锁”在锁是可获取状态时,不管自己是不是在队列的开头都会获取锁。 以对象的方式来操作对象锁,相对于sychronized需要在finally中去释放锁。

synchronized和ReentrantLock的区别

除了synchronized的功能,多了三个高级功能。 等待可中断,公平锁,绑定多个Condition。 1. 等待可中断:在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待,tryLock(long timeout, TimeUnit unit) 2. 公平锁:按照申请锁的顺序来一次获得锁称为公平锁,synchronized的是非公平锁,ReentrantLock可以通过构造函数实现公平锁。new RenentrantLock(boolean fair) 3. 绑定多个Condition:通过多次newCondition可以获得多个Condition对象,可以简单的实现比较负责的线程同步的功能,通过await(),signal();

实现消费者模式

sychronized

public static class Depot { PRivate int mCapacity; private int mSize; public Depot(int capacity) { mCapacity = capacity; mSize = 0; } public synchronized void produce(int val) { try { int left = val; while (left > 0) { while (mSize >= mCapacity) wait(); int inc = (mSize + left) > mCapacity ? (mCapacity - mSize) : left; mSize += inc; left -= inc; System.out.println("produce Thread: " + Thread.currentThread().getName() + " val: " + val + " mSize: " + mSize + " left: " + left); notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void consume(int val) { try { int left = val; while (left > 0) { while (mSize <= 0) wait(); int inc = (mSize - left) < 0 ? mSize : left; mSize -= inc; left -= inc; System.out.println("consume Thread: " + Thread.currentThread().getName() + " val: " + val + " mSize: " + mSize + " left: " + left); notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } } private static class Producer { private Depot depot; public Producer(Depot depot) { this.depot = depot; } public void produce(int val) { new Thread() { @Override public void run() { depot.produce(val); } }.start(); } } static class Customer { private Depot depot; public Customer(Depot depot) { this.depot = depot; } public void consume(int val) { new Thread() { @Override public void run() { depot.consume(val); } }.start(); } } public static void main(String[] args) { Depot depot = new Depot(100); Producer producer = new Producer(depot); Customer customer = new Customer(depot); producer.produce(60); producer.produce(120); customer.consume(90); customer.consume(150); producer.produce(110); }

ReentrantLock

public static class Depot { private int mCapacity; private int mSize; private Lock mLock; private Condition mFullCondition; private Condition mEmptyCondition; public Depot(int capacity) { mCapacity = capacity; mSize = 0; mLock = new ReentrantLock(); mFullCondition = mLock.newCondition(); mEmptyCondition = mLock.newCondition(); } public void produce(int val) { mLock.lock(); try { int left = val; while (left > 0) { while (mSize >= mCapacity) mFullCondition.await(); int inc = (mSize + left) > mCapacity ? (mCapacity - mSize) : left; mSize += inc; left -= inc; System.out.println("produce Thread: " + Thread.currentThread().getName() + " mSize: " + mSize + " left: " + left); mEmptyCondition.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { mLock.unlock(); } } public void consume(int val) { mLock.lock(); try { int left = val; while (left > 0) { while (mSize <= 0) mEmptyCondition.await(); int inc = (mSize - left) < 0 ? mSize : left; mSize -= inc; left -= inc; System.out.println("consume Thread: " + Thread.currentThread().getName() + " mSize: " + mSize + " left: " + left); mFullCondition.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { mLock.unlock(); } } } static class Producer { private Depot depot; public Producer(Depot depot) { this.depot = depot; } public void produce(int val) { new Thread() { @Override public void run() { depot.produce(val); } }.start(); } } static class Customer { private Depot depot; public Customer(Depot depot) { this.depot = depot; } public void consume(int val) { new Thread() { @Override public void run() { depot.consume(val); } }.start(); } } public static void main(String[] args) { Depot depot = new Depot(100); Producer producer = new Producer(depot); Customer customer = new Customer(depot); producer.produce(60); producer.produce(120); customer.consume(90); customer.consume(150); producer.produce(110); }