Lock比synchronized更加面向对象,对比synchronized我们直接上代码
Lock lock = new ReentrantLock();
public void output(String name){
int len = name.length();
lock.lock();
try{
for(int i=0;i
相对于synchronized,ReentrantLock可中断响应、锁申请等待限时、公平锁。另外可以结合Condition来使用,使其更是逼格满满。参考https://blog.csdn.net/Somhu/article/details/78874634
解释下中断响应interrupt()方法,主动中断线程;
申请等待限时,
可以使用 tryLock()或者tryLock(long timeout, TimeUtil unit) 方法进行一次限时的锁等待。前者不带参数,这时线程尝试获取锁,如果获取到锁则继续执行,如果锁被其他线程持有,则立即返回 false ,也就是不会使当前线程等待,所以不会产生死锁。
后者带有参数,表示在指定时长内获取到锁则继续执行,如果等待指定时长后还没有获取到锁则返回false;
公平锁,即fair
所谓公平锁,就是按照时间先后顺序,使先等待的线程先得到锁,而且,公平锁不会产生饥饿锁,也就是只要排队等待,最终能等待到获取锁的机会。使用重入锁(默认是非公平锁)创建公平锁:
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
多个读锁不互斥,写锁与读锁和写锁都互斥,由jvm控制
看下手册给的例子:
class CachedData {
Object data;
volatile boolean cacheValid;
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// upgrade lock manually
rwl.readLock().unlock(); // must unlock first to obtain writelock
rwl.writeLock().lock();
if (!cacheValid) { // recheck
data = ...
cacheValid = true;
}
// downgrade lock
rwl.readLock().lock(); // reacquire read without giving up write lock
rwl.writeLock().unlock(); // unlock write, still hold read
}
use(data);
rwl.readLock().unlock();
}
}
初始只能认为是挂读锁,判断若是读锁,则开读锁,挂写锁,再加一遍判断保险;最后挂读锁,开写锁(开之前的写锁降级);
这里给个缓存的小案例:出自张孝祥老师之手
public class CacheDemo {
private Map cache = new HashMap();
public static void main(String[] args) {
// TODO Auto-generated method stub
}
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public Object getData(String key){
rwl.readLock().lock();
Object value = null;
try{
value = cache.get(key);
if(value == null){
rwl.readLock().unlock();
rwl.writeLock().lock();
try{
if(value==null){//再判断一次,防止多个线程写入覆盖
value = "aaaa";//实际是去queryDB();查数据库
}
}finally{
rwl.writeLock().unlock();
}
rwl.readLock().lock();
}
}finally{
rwl.readLock().unlock();
}
return value;
}
}
Condition的通信,结合ReentrantLock实现线程通信
public static void main(String[] args) {
final Business business = new Business();
new Thread(() -> {
for (int i = 1; i <= 50; i++) {
business.sub(i);
}
}
).start();
for (int i = 1; i <= 50; i++) {
business.main(i);
}
}
static class Business {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
private boolean bShouldSub = true;
public void sub(int i) {
lock.lock();
try {
while (!bShouldSub) {
try {
condition.await();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
condition.signal();
} finally {
lock.unlock();
}
}
public void main(int i) {
lock.lock();
try {
while (bShouldSub) {
try {
condition.await();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int j = 1; j <= 100; j++) {
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
bShouldSub = true;
condition.signal();
} finally {
lock.unlock();
}
}
}
}
condition的await()类似于Object的wait();等待
condition的signal()类似于Object的notify();唤醒
对比的学还是简单店点。锁结合condition实现线程间通信。
参看手册Condition提供的例子,提供了阻塞队列的例子(java已经提供了ArrayBlockingQueue),下例只是体会condition的这个例子。
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();
}
}
}
利用condition给出三个线程按顺序调用的例子
public class ThreeConditionCommunication {
/**
* @param args
*/
public static void main(String[] args) {
final Business business = new Business();
new Thread(
() -> {
for (int i = 1; i <= 50; i++) {
business.sub2(i);
}
}
).start();
new Thread(
() -> {
for (int i = 1; i <= 50; i++) {
business.sub3(i);
}
}
).start();
for (int i = 1; i <= 50; i++) {
business.main(i);
}
}
static class Business {
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
private int shouldSub = 1;
public void sub2(int i) {
lock.lock();
try {
while (shouldSub != 2) {
try {
condition2.await();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println("sub2 thread sequence of " + j + ",loop of " + i);
}
shouldSub = 3;
condition3.signal();
} finally {
lock.unlock();
}
}
public void sub3(int i) {
lock.lock();
try {
while (shouldSub != 3) {
try {
condition3.await();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int j = 1; j <= 20; j++) {
System.out.println("sub3 thread sequence of " + j + ",loop of " + i);
}
shouldSub = 1;
condition1.signal();
} finally {
lock.unlock();
}
}
public void main(int i) {
lock.lock();
try {
while (shouldSub != 1) {
try {
condition1.await();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int j = 1; j <= 100; j++) {
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
shouldSub = 2;
condition2.signal();
} finally {
lock.unlock();
}
}
}
}