先看一下使用Lock的例子(javaDoc的例子):
其实看下java.util.concurrent.ArrayBlockingQueue的代码,就会发现,下面的put/take方法其实就是java.util.concurrent.ArrayBlockingQueue的put/take方法的实现。
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class BoundedBuffer { final Lock lock = new ReentrantLock(); //一个Lock可以对应多个Condition,但一个Condition只能对应一个Lock //Condition对象可以细化等待(Condition.await()/Object.wait())和通知(Condition.signalAll()/Object.notifyAll())的粒度。 //例如这里的notFull、notEmpty,当调用Condition.await()之后,只有接收到对应的Condition的signalAll()才能继续。这一点是synchronized不能实现的 final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[2]; int putIndex, takeIndex, count; public void put(Object x) throws InterruptedException { lock.lock();//必须手动获取锁 try { while (count == items.length){ notFull.await();//等待在notFull这个Condition的通知 } items[putIndex] = x; if (++putIndex == items.length){ putIndex = 0; } ++count; notEmpty.signalAll();//通知等待在notEmpty这个Condition上面的线程 } finally { lock.unlock();//必须手动释放锁 } } public Object take() throws InterruptedException { lock.lock();//必须手动获取锁 try { while (count == 0){ notEmpty.await();//等待在notEmpty这个Condition的通知 } Object x = items[takeIndex]; if (++takeIndex == items.length){ takeIndex = 0; } --count; notFull.signalAll();//通知等待在notFull这个Condition上面的线程 return x; } finally { lock.unlock();//必须手动释放锁 } } }
然后是使用synchronized关键字的例子:
class BoundedBuffer2 { final Object[] items = new Object[2]; int putIndex, takeIndex, count; /** * 锁定对象(每个对象都有一个对应的锁) */ private static final Object monitor = new Object(); public void put(Object x) throws InterruptedException { //synchronized(monitor)这句话就包含了获取monitor的锁,相当于monitor对应的lock的lock.lock() //并且synchronized会在锁定的方法或者代码块结束之后,自动释放对象的锁(lock.unlock()) synchronized(monitor){ while (count == items.length){ monitor.wait(); } items[putIndex] = x; if (++putIndex == items.length){ putIndex = 0; } ++count; monitor.notifyAll();//对应上面例子中的signalAll } } public Object take() throws InterruptedException { Object x = null; //synchronized(monitor)这句话就包含了获取monitor的锁,相当于monitor对应的lock的lock.lock() //并且synchronized会在锁定的方法或者代码块结束之后,自动释放对象的锁(lock.unlock()) synchronized(monitor){ while (count == 0){ monitor.wait(); } x = items[takeIndex]; if (++takeIndex == items.length){ takeIndex = 0; } --count; monitor.notifyAll();//对应上面例子中的signalAll } return x; } }
测试:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test { public static void main(String[] args) throws Exception { m(); } static ExecutorService e =Executors.newFixedThreadPool(5); static BoundedBuffer2 b2 = new BoundedBuffer2(); static BounderBuffer b = new BounderBuffer(); static void m(){ int aaa=3; while(aaa-->0){ remove(); add(aaa); } e.shutdown(); } static void remove(){ e.execute(new Runnable(){ public void run(){ try { System.out.println("take : "+b.take()); System.out.println("take : "+b2.take()); } catch (InterruptedException e) { e.printStackTrace(); } } }); } static void add(final int i){ e.execute(new Runnable(){ public void run(){ try { System.out.println("add : "+i); b.put(i); //b2.put(i); } catch (InterruptedException e) { e.printStackTrace(); } } }); } }
从结果看,两个例子功能是一样的。
不同的是:Lock的方式必须手动的获取/释放锁,而使用synchronized的方式则不需要,因为它自动包含了获取/释放锁的过程(这也是为什么推荐使用后者,因为它简单,易操作,但是对于需要细粒度的控制同步操作的时候,还是要使用前者)
另外,使用Lock的时候,等待/通知 是使用的Condition对象的await()/signal()/signalAll() ,而使用synchronized的时候,则是对象的wait()/notify()/notifyAll();由此可以看出,使用Lock的时候,粒度更细了,一个Lock可以对应多个Condition,
当需要等待某个条件满足的时候,就使用该条件的Condition的await(),等待其它线程调用该Condition的signal()/signalAll()
个人的初步理解。
下面是一个问题和答案,同时也解决了自己的疑惑:
下面的代码是Condition类的javadoc中的一个示例
:
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(); } } 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(); } } }
假设有两个线程:生产者、消费者,分别调用某个BoundedBuffer对象
的put()和take()方法
如果消费者先执行,调用了该对象的take()方法,并且运行到了while循环处的notEmpty.await();
那么此时,消费者是已经得到了lock的,那为什么生产者却可以进到put()方法的内部,并且获得lock呢?
原因:
Lock
and synchronized
在等待的时候,都会释放对象的锁的。
例如:Object.wait()就会释放synchronized的锁,Condition.await()会释放对应的Lock的锁。
Both Lock
and synchronized
temporarily allow others to obtain the lock when they are waiting. To stop waiting, a thread have to re-acquire the lock.
Note: They don't release it fully and if you take a stack trace you can have multiple threads which appear to be holding the lock at once, but at most one of them will be running (the rest will be waiting)
From Condition.await()
The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:
- Some other thread invokes the signal() method for this Condition and the current thread happens to be chosen as the thread to be awakened; or
- Some other thread invokes the signalAll() method for this Condition; or
- Some other thread interrupts the current thread, and interruption of thread suspension is supported; or
- A "spurious wakeup" occurs.
In all cases, before this method can return the current thread must re-acquire the lock associated with this condition. When the thread returns it is guaranteed to hold this loc
相关推荐
基础理论知识,描述lock和synchronized的区别和基础的理论,其中还有死锁等基础概念。
lock锁,lock锁和synchronized的对比 # Lock锁 JDK5.0后Java提供了一种更加强大的线程同步机制。一种显式定义同步锁对象来实现锁,提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问...
【Java面试题】lock与synchronized区别
目录synchronized的缺陷Lock和ReentrantLock常用方法ReadWriteLock和ReentrantReadWriteLockLock和synchronized区别synchronized锁升级公平锁和非公平锁 synchronized的缺陷 众所周知,synchronized锁是JAVA的关键字...
而Lock接口则是一个更底层的同步机制,它提供了更丰富的功能,但需要显式地获取和释放锁,通常通过实现类如ReentrantLock来使用。 其次,从功能特性上来看,synchronized具有可重入性,即同一个线程可以多次获取同...
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
java的线程同步机制synchronized关键字的理解_.docx
并发编程中,锁是经常需要用到的,今天我们一起来看下Java中的锁机制:synchronized和lock。 Synchronized 和 Lock的概念 Synchronized 是Java 并发编程中很重要的关键字,另外一个很重要的是 volatile。Syncronized...
线程同步Synchronized,监视器monitor和锁lock的关系2---马克-to-win java视频
线程同步Synchronized,监视器monitor和锁lock的关系2---马克-to-win java视频
java同步synchronized关键字用法示例
基于Java synchronized同步锁实现线程交互.pdf
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
之前已经说道,JVM提供了synchronized关键字来实现对变量的同步访问以及用wait和notify来实现线程间通信。在jdk1.5以后,JAVA提供了Lock类来实现和synchronized一样的功能,并且还提供了Condition来显示线程间通信。...
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
个人对synchronized 的理解,可以参考下!!