除了咱们常常用的
synchronized
关键字(结合Object
的wait()
和notify()
使用)以外,还有对应的上篇文章讲到的方法JAVA并发之多线程基础(1)以外,咱们平常中使用到最多的也就是JUC下面对应的类与方法。java
ReentrantLock
在JDK1.5以前比Synchronized
性能好许多,在以后Synchronized
也进行了修改,使得当下两个在对于线程方面性能相差无几。可是ReentrantLock
的功能更加丰富,它的特色有:可重入、可中断、可限时、公平锁。多线程
package com.montos.lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static int k = 0;
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
lock.lock();
k++;
}
for (int i = 0; i < 1000; i++) {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockDemo demo = new ReentrantLockDemo();
Thread t1 = new Thread(demo);
Thread t2 = new Thread(demo);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(k);
}
}
复制代码
经过这个小的demo能够看到控制台中不管如何执行,输出的值都是2000。这里面就体现了可重入(对于同一把锁进行加锁和释放锁)的特色。并发
可中断则在lockInterruptibly()
这个方法上进行体现。ide
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
复制代码
使用这个方法就能够在加锁的过程当中进行中断,用来保证程序的正常进行下去,避免死锁一直阻塞程序运行。经过上面的方法进行查看底层调用的:函数
//以独占模式获取,若是中断将停止。
public final void acquireInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted()) //测试当前线程是否已中断
throw new InterruptedException();
if (!tryAcquire(arg)) //尝试获取arg次锁操做
doAcquireInterruptibly(arg);//以独占中断模式获取锁操做
}
复制代码
tryLock(long timeout, TimeUnit unit)
方法中体现,目的主要是防止死锁的发生。public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
复制代码
在使用这个的时候,也要注意在
finally
中也要释放锁,固然在释放以前先判断当前当前线程是否持有锁操做lock.isHeldByCurrentThread()
。post
ReentrantLock
的构造函数中体现出来。所谓公平锁与非公平锁就是线程先来先到和先来不必定拿到锁的状况的。public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
复制代码
固然非公平锁的性能要比公平锁的性能好不少,公平锁里面还要维护一个队列(AQS)来进行操控公平性。因此说通常没有特殊要求的状况下,默认使用非公平的锁就能够。性能
上面讲完重入锁以后,这里在讲解一个与重入锁密切相关的类。他与重入锁之间的关系犹如
synchronized
与Object
的wait()
和notify()
同样。也就是说在使用它的状况也要得到当前的锁,才能够进行下面的操做。测试
package com.montos.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockCondition implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();
@Override
public void run() {
try {
lock.lock();//拿到对应锁
condition.await();
System.out.println("wait is end,going down");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockCondition conditions = new ReentrantLockCondition();
Thread thread = new Thread(conditions);
thread.start();
Thread.sleep(2000);
lock.lock();
condition.signal();//只有拿到对应锁上面的监视器才能够执行
lock.unlock();
}
}
复制代码
这上面的
Condition
的用法至关于Object
里面的两个方法同样。整体来讲使用重入锁也是看业务场景状况下使用,若是想要上面特色的锁方法,那么使用重入锁就是很好的。否则的话使用synchronized
关键字就能够完成大多数的业务场景了。ui