在Java多线程中,我们会遇到多个线程访问同一个资源,产生竞争,如果操作不到会导致死锁的产生,例如在现实中的十字路口,锁就像红路灯指示器,一旦锁坏了,就会导致交通瘫痪。
通过本篇文章读者可以学到以下内容
- 多线程并发
- 锁的使用
- 超时锁
一、编写锁的接口
public interface Lock {
//自定义异常类
public static class TimeOutException extends Exception{
public TimeOutException(String message){
super(message);
}
}
//无超时锁,可以被打断
void lock() throws InterruptedException;
//超时锁,可以被打断
void lock(long molls) throws InterruptedException,TimeOutException;
//解锁
void unlock();
//获取当前等待的线程
Collection<Thread> getBlockedThread();
//获取当前阻塞的线程数目
int getBlockSize();
}
二、实现接口,编写功能
首先介绍几个重要的方法属性
1,Monitor这里选择的是BooleanLock
,使用this.wait()
来阻塞,
2,因为是多线程访问,因此使用Collection来存储等待的线程
3,使用while(initValue),通过标志位initValue来判断当前线程是否在工作中,以进行后面的操作
4,所谓超时锁就是设置超时时间,如果超过这读段时间,抛出异常
public class BooleanLock implements Lock{
private boolean initValue;
private Thread currenThread;
public BooleanLock(){
this.initValue = false;
}
private Collection<Thread> blockThreadCollection = new ArrayList<>();
@Override
public synchronized void lock() throws InterruptedException {
while (initValue){
blockThreadCollection.add(Thread.currentThread());
this.wait();
}
//表明此时正在用,别人进来就要锁住
this.initValue = true;
currenThread = Thread.currentThread();
blockThreadCollection.remove(Thread.currentThread());//从集合中删除
}
@Override
public synchronized void lock(long mills) throws InterruptedException, TimeOutException {
if (mills<=0){
lock();
}else {
long hasRemain = mills;
long endTime = System.currentTimeMillis()+mills;
while (initValue){
if (hasRemain<=0)
throw new TimeOutException("Time out");
blockThreadCollection.add(Thread.currentThread());
hasRemain = endTime-System.currentTimeMillis();
}
this.initValue = true;
currenThread = Thread.currentThread();
}
}
@Override
public synchronized void unlock() {
if (currenThread==Thread.currentThread()){
this.initValue = false; //表明锁已经释放
Optional.of(Thread.currentThread().getName()+ " release the lock monitor").ifPresent(System.out::println);
this.notifyAll();
}
}
@Override
public Collection<Thread> getBlockedThread() {
return Collections.unmodifiableCollection(blockThreadCollection);
}
@Override
public int getBlockSize() {
return blockThreadCollection.size();
}
}
三、测试
public class BlockTest {
public static void main(String[] args) throws InterruptedException {
final BooleanLock booleanLock = new BooleanLock();
// 使用Stream流的方式房间四个线程
Stream.of("T1","T2","T3","T4").forEach(name->{
new Thread(()->{
try {
booleanLock.lock(10);
Optional.of(Thread.currentThread().getName()+" have the lock Monitor").ifPresent(System.out::println);
work();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Lock.TimeOutException e) {
Optional.of(Thread.currentThread().getName()+" time out").ifPresent(System.out::println);
} finally {
booleanLock.unlock();
}
},name).start();
});
}
private static void work() throws InterruptedException{
Optional.of(Thread.currentThread().getName()+" is working.....'").ifPresent(System.out::println);
Thread.sleep(40_000);
}
}
结果:
T1 have the lock Monitor
T1 is working.....'
T2 time out
T4 time out
T3 time out
备注: 如果是需要一直等待就调用 lock()
,如果是超时要退出来就调用超时lock(long millo)