目录:
1. java lock介绍
2.java lock的使用
一. java lock介绍:
并发场景中,最简单的方式是直接添加同步关键字synchronized来实现多线程之间的同步互斥操作。另外一种高效的机制去完成”同步互斥”操作是使用Lock对象,比synchronized关键字更为强大功能,并且有嗅探锁定,多路分支等功能。
在java.util.concurrent.locks包中有很多Lock的实现类,常用的有ReentrantLock、ReadWriteLock(实现类ReentrantReadWriteLock),其实现都依赖java.util.concurrent.AbstractQueuedSynchronizer类,实现思路都大同小异。
二. java lock使用:
2.1 ReentrantLock:
使用synchronized 关键字进行多线程协同工作时,需要使用Object wait()阻塞释放锁,notify()唤醒,不释放锁等进行配合使用。
使用Lock时可以使用新的等待/通知类,Condition,Condition一定是针对某一把固定的锁,也就是说,只有在有锁的基础上才会产生Condition。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTest {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void test1() {
try {
// 加锁
lock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入等待狀態..");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "釋放鎖..");
// 释放锁,类似于 Object wait,阻塞于此
condition.await();
System.out.println("当前线程:" + Thread.currentThread().getName() +"继续执行...");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 一定要释放锁,否则其他线程拥有无法获取
lock.unlock();
}
}
public void test2() {
try {
// 加锁
lock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入test2..");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "發出喚醒..");
//不释放锁类,似于Object notify
condition.signal();
System.out.println("当前线程:" + Thread.currentThread().getName() +"沒有釋放鎖...");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 一定要释放锁,否则其他线程拥有无法获取
lock.unlock();
}
}
public static void main (String[] args) {
final ReentrantLockTest uc = new ReentrantLockTest();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
uc.test1();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
uc.test2();
}
}, "t2");
t1.start();
t2.start();
}
}
2.2 ReentrantReadWriteLock
读写锁:实现读写分离,适用高并发下读多写少的场景。
synchronized关键字和ReentrantLock 同一时间只能有一个线程进行访问被锁定的代码,而读写锁的机制则不同,它有两把锁,读锁和写锁,在读锁情况下,多个线程可以并发访问资源,只有当是写锁时只能一个一个的顺序执行。
规则是:读读共享,写写互斥,读写互斥。
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReentrantReadWriteLockTest {
private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
private ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
public void readOp() {
try {
readLock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
public void writeOp() {
try {
writeLock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
public static void main (String[] args) {
final ReentrantReadWriteLockTest lockTest = new ReentrantReadWriteLockTest();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
lockTest.readOp();
}
}, "rop1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
lockTest.readOp();
}
}, "rop2");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
lockTest.writeOp();
}
}, "wop3");
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
lockTest.writeOp();
}
}, "wop4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
运行结果: 可见rop1 与rop2 同时执行, wop3、wop4互斥执行.......
当前线程:rop2进入...
当前线程:rop1进入...
当前线程:rop1退出...
当前线程:rop2退出...
当前线程:wop3进入...
当前线程:wop3退出...
当前线程:wop4进入...
当前线程:wop4退出...