一、 自定义Boolean锁

需求

  • 设置一个锁,让只有一个线程可以工作,其他的线程阻塞
  • 可以查看都有哪些线程阻塞
  • 只用加锁的线程才可以释放锁,其他线程不允许修改

先定义一个接口,定义锁的规范

public interface Lock {

    void lock() throws InterruptedException;


    void unlock();

    Collection<Thread> getBlockedThread();

    int getBolckedSize();

}

定义借口的实现类,实现相关需求

public class BooleanLock implements Lock {

    private boolean initValue;//false时为该锁被释放,true时代表被占有

    private Thread currentThread;

    private Collection<Thread> blockedThreadCollection = new ArrayList<>();

    public BooleanLock() {
        this.initValue = false;
    }

    @Override
    public synchronized void lock() throws InterruptedException {//抢锁
        while (initValue) {//此时如果没有抢到锁
            blockedThreadCollection.add(Thread.currentThread());
            this.wait();
        }
        blockedThreadCollection.remove(Thread.currentThread());
        this.initValue = true;
        this.currentThread = Thread.currentThread();//保存抢到锁的线程
    }



    @Override
    public synchronized void unlock() {
        if (currentThread == Thread.currentThread()) {//防止其他线程把正在执行的线程锁释放
            this.initValue = false;
            System.out.println(Thread.currentThread().getName() + "释放");
            this.notifyAll();
        }else {
            System.out.println("您没有释放的权限!!!");

        }
    }

    @Override
    public Collection<Thread> getBlockedThread() {
        return Collections.unmodifiableCollection(blockedThreadCollection);
    }

    @Override
    public int getBolckedSize() {
        return blockedThreadCollection.size();
    }
}

实现方式

  • 通过synchronized保护一个Boolean的变量,如果为false,表示这个锁还有没占用
  • 如果为true,线程陷入休眠,将该线程加入到阻塞队列
  • 当线程执行完毕,将Boolean的变量至为false,表示释放这个锁,同时唤醒其他阻塞线程
  • 如果线程抢到了锁,则退出阻塞队列,并且在锁中定义一个属性,保存当前抢到锁的线程是哪个
  • 在释放锁的时候,检查是否是抢到锁的线程想要释放该锁,如果不是,拒绝释放

测试

public class LockTest {

    public static void main(String[] args) throws InterruptedException {

        final BooleanLock booleanLock = new BooleanLock();
        Stream.of("T1","T2","T3","T4","T5")
                .forEach(name->
            new Thread(()->{
                try {
                    booleanLock.lock();
                    System.out.println(Thread.currentThread().getName() + "抢到了锁~");
                    work();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    booleanLock.unlock();
                }
            },name).start()
        );


        Thread.sleep(100);

        booleanLock.unlock();
    }

    private static void work(){
        System.out.println(Thread.currentThread().getName() + "正在工作....");
        try {
            Thread.sleep(10_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

结果

T1抢到了锁~
T1正在工作…
您没有释放的权限!!!
T1释放
T5抢到了锁~
T5正在工作…
T5释放
T2抢到了锁~
T2正在工作…
T2释放
T4抢到了锁~
T4正在工作…
T4释放
T3抢到了锁~
T3正在工作…
T3释放

分析

  • 可以发现只有一个线程在工作,每当其释放锁,其他的线程才能继续工作
  • 当主线程想要释放锁时,被提示没有权限

二、 捕获线程中的异常

需求

  • 由于无论是覆写run方法或者还是传递一个Runnable接口实例,都无法捕获线程中出现的异常
  • Thread提供了一个实例方法:setUncaughtExceptionHandler可以由开发者完全的控制所有没有捕获到的异常
public class ThreadException {

    private static int A = 10;
    private  static int B = 0;

    public static void main(String[] args) {
        Thread t = new Thread(()->{
            try {
                Thread.sleep(5000);
                int result = A/B;

                System.out.println(result);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });

        t.setUncaughtExceptionHandler((Thread,e)->{//处理未捕获的异常
            System.out.println(e);//打印异常
            System.out.println(Thread.getName());//打印出现异常的线程名称
        });

        t.start();
    }

}

结果

java.lang.ArithmeticException: / by zero
Thread-0

若想深入学习,参考下面的博客

参考博客