Java优雅的实现锁和超时锁

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jeekmary/article/details/95346038

在Java多线程中,我们会遇到多个线程访问同一个资源,产生竞争,如果操作不到会导致死锁的产生,例如在现实中的十字路口,锁就像红路灯指示器,一旦锁坏了,就会导致交通瘫痪。

通过本篇文章读者可以学到以下内容

  1. 多线程并发
  2. 锁的使用
  3. 超时锁

一、编写锁的接口

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)

展开阅读全文

没有更多推荐了,返回首页