- 使用ReentrantLock类
- 使用ReentrantReadWriteLock类
1.使用ReentrantLock类
样例代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BusinessService {
private Lock lock=new ReentrantLock();
public void service() {
lock.lock();
for(int i=0;i<5;i++) {
System.out.println("service in " + Thread.currentThread().getName());
}
lock.unlock();
}
}
lock.lock() 和 lock.unlock()之间属于同步区域,跟synchronized(x){ }的同步区域是类似的。使用这种锁也是可以创建 等待 / 通知模型的。它是完全互斥排他的。样例代码如下所示:
共享服务的bean:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BusinessService {
private Lock lock=new ReentrantLock();
private Condition addCon=lock.newCondition();
private Condition minCon=lock.newCondition();
private int i=10;
public void addMore() {
lock.lock();
if(i>13) {
try {
minCon.signalAll();
addCon.await();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}else {
i=i+1;
System.out.println(Thread.currentThread().getName() + " add 1, then i is : "+i);
}
lock.unlock();
}
public void minusMore() {
lock.lock();
if(i<7) {
try {
addCon.signalAll();
minCon.await();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}else {
i=i-1;
System.out.println(Thread.currentThread().getName() + " minus 1 , then i is : "+i);
}
lock.unlock();
}
}
线程bean:
public class LockServiceThread implements Runnable{
private BusinessService service;
public LockServiceThread(BusinessService bs) {
this.service=bs;
}
@Override
public void run() {
while(true) {
service.addMore();
}
}
}
public class LoclServiceThread2 implements Runnable{
private BusinessService service;
public LoclServiceThread2(BusinessService bs) {
this.service=bs;
}
@Override
public void run() {
while(true) {
service.minusMore();
}
}
}
测试bean:
public class ThreadSample {
public static void main(String[] args) {
BusinessService bs=new BusinessService();
ArrayList<Thread> list=new ArrayList<Thread>();
for(int i=0;i<2;i++) {
list.add(new Thread(new LockServiceThread(bs)));
list.add(new Thread(new LoclServiceThread2(bs)));
}
for(int i=0;i<list.size();i++) {
list.get(i).start();
}
}
}
公平锁是表示线程获得锁的顺序是按照线程加锁的顺序来分配的,按照先进先出的顺序。非公平锁就是一种获取锁的抢占机制,随机获得锁。设置锁为公平锁的语句是:
private Lock lock=new ReentrantLock(true);
设置锁为非公平锁的语句是,默认是非公平锁:
private Lock lock=new ReentrantLock(false);
lock.getHoldCount();// 查询当前线程保持此锁定的个数,也是调用lock.lock()的次数
lock.getQueueLength();//正等待获得此锁的线程估计数
lock.getWaitQueueLength(); //获取等待此锁相关的给定条件Condition的线程估计数
lock.hasQueuedThread(thread);//查询指定线程是否正在获取此锁
lock.hasQueuedThreads;//查询是否有线程正在等待获取此锁
lock.hasWaiters(condition);//查询是否有线程正在等待此锁有关的condition条件
lock.isFair();//判断此锁是不是公平锁
lock.isHeldByCurrentThread();//查询当前线程是否保持此锁
lock.isLocked();//查询此锁是否由任意线程保持
lock.lockInterruptibly();//如果当前啊线程未被中断,则获取锁;如果已经中断则抛出异常
lock.tryLock();//在调用的时候,锁未被另一个线程保持的情况下,才获取该锁
lock.tryLock(timeout,unit);//如果锁在给定时间内未被另一个线程保持且当前线程未被中断,则获取锁
condition.awaitUninterruptibly();//在被唤醒或者是打断之前,条件一直处于等待状态
condition.awaitUntil(time);//条件在某个时间之前,一直处于等待状态
2.使用ReentrantReadWriteLock类
由于ReentrantLock的锁是完全互斥排他的,所以同一时间只有一个线程正在执行同步区域的代码,为了提高运行的效率,引入了ReentrantReadWriteLock这种读写锁的机制。这种读写锁的机制有两个锁,第一种锁是与读操作相关的锁,叫做共享锁;第二种锁是与写操作相关的锁,叫做排它锁。多个读锁之间是不互斥的,读锁和写锁是互斥的,写锁和写锁是互斥的。
下面是使用这种锁改写的服务类:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class BusinessService {
private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
private Condition addCon=lock.writeLock().newCondition();
private Condition minCon=lock.writeLock().newCondition();
private int i=10;
public void addMore() {
lock.writeLock().lock();;
if(i>13) {
try {
minCon.signalAll();
addCon.await();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}else {
i=i+1;
System.out.println(Thread.currentThread().getName() + " add 1, then i is : "+i);
}
lock.writeLock().unlock();
}
public void minusMore() {
lock.writeLock().lock();
if(i<7) {
try {
addCon.signalAll();
minCon.await();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}else {
i=i-1;
System.out.println(Thread.currentThread().getName() + " minus 1 , then i is : "+i);
}
lock.writeLock().unlock();
}
public void readNum() {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + " read i, then i is : "+i);
lock.readLock().unlock();
}
}