API层面
这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,底层借助AQS实现,需要lock()和unlock()方法配合try/finally语句块来完成。
synchronized既可以修饰方法,也可以修饰代码块。
//synchronized修饰一个方法时,这个方法叫同步方法。
public synchronized void test() {
//方法体``
}
synchronized(Object) {
//括号中表示需要锁的对象.
//线程执行的时候会对Object上锁
}
ReentrantLock使用
private ReentrantLock lock = new ReentrantLock();
public void run() {
lock.lock();
try{
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}finally{
lock.unlock();
}
}
等待可中断
使用synchronized。如果Thread1不释放,Thread2将一直等待,不能被中断。synchronized也可以说是Java提供的原子性内置锁机制。内部锁扮演了互斥锁(mutual exclusion lock ,mutex)的角色,一个线程引用锁的时候,别的线程阻塞等待。
synchronized执行时如果抛出异常交给jvm处理,会释放锁,因此碰到异常时要小心处理。
使用ReentrantLock。如果Thread1不释放,Thread2等待了很长时间以后,可以中断等待,转而去做别的事情。
void lockInterruptibly() throws InterruptedException;
公平锁
synchronized的锁是非公平锁,ReentrantLock默认情况下也是非公平锁,但可以通过带布尔值的构造函数要求使用公平锁。
ReentrantLock 构造器的一个参数是boolean值,它允许您选择想要一个公平(fair)锁,还是一个不公平(unfair)锁。公平锁:使线程按照请求锁的顺序依次获得锁, 效率比非公平锁低。
锁绑定多个条件
ReentrantLock可以同时绑定多个Condition对象,只需多次调用newCondition方法即可。
synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含的条件。但如果要和多于一个的条件关联的时候,就不得不额外添加一个锁。
ReentrantLock更灵活
可以设置尝试获取锁的时间:
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;