Java知识分享
热爱技术,分享技术

自定义显示锁BooleanLock

synchronized是java多线程里面一个比较很重要的关键字,它提供了一种排他式的同步机制,在某个时间内,如果其中一个线程获取了锁,那么其他线程试图获取锁,就会进入阻塞状态,等到某个线程释放了锁才能获取锁。

而这种阻塞有两个比较明显的缺点:

  1. 无法控制阻塞时长
  2. 阻塞不可中断

利用java多线程的知识,可以自己动手构造一个BooleanLock,使其在具有synchronized功能的基础之上又具备可中断和超时的功能。

Lock接口

自定义显示锁BooleanLock插图
  • lock()方法永远会阻塞,除非获取到了锁,这一点和synchronized非常类似,但是该方法是可以被中断的,中断时会抛出InterruptedException
  • lock(long mills)方法除了可以被中断以外,还增加了对应的超时功能。
  • unlock()方法可用来进行锁的释放。
  • getBlockedThreads用于获取当前有哪些线程被阻塞

BooleanLock实现

package com.ibfbc.concurrency;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeoutException;

import static java.lang.System.currentTimeMillis;
import static java.lang.Thread.currentThread;

public class BooleanLock implements Lock {

    //当前线程
    private Thread currentThread;
    //是否上锁
    private boolean locked = false;
    //哪些进程进入了阻塞
    private final List<Thread> blockedList = new ArrayList<>();

    @Override
    public void lock() throws InterruptedException {
        synchronized (this){
            //获取当前线程
            final Thread tempThread = currentThread();
            //线程是否进入了阻塞状态,如果进入了加入阻塞队列
            while (locked){
                try {
                    if (!blockedList.contains(tempThread)){
                        blockedList.add(tempThread);
                    }
                    this.wait();
                }catch (InterruptedException e){
                    //被中断后移除阻塞队列
                    blockedList.remove(currentThread());
                    throw e;
                }

            }
            //如果当前线程没有获取锁,则拿到锁,移除阻塞队列
            blockedList.remove(currentThread());
            this.locked = true;
            this.currentThread = currentThread();
        }
    }

    @Override
    public void lock(long mills) throws InterruptedException, TimeoutException {
        synchronized (this){
            //判断设置超时时间是否<=0
            if (mills<=0){
                this.lock();
            }else {
                long remainingMills = mills;
                long endMills = currentTimeMillis() +remainingMills;
                //该方法同上面一样,加入了计时功能
                while (locked){
                    if (remainingMills<=0){
                        throw new TimeoutException("不能获得锁");
                    }
                    if (!blockedList.contains(currentThread())){
                        blockedList.add(currentThread());
                        this.wait(remainingMills);
                        remainingMills = endMills - currentTimeMillis();
                    }
                }
                blockedList.remove(currentThread());
                this.locked = true;
                this.currentThread = currentThread();
            }
        }
    }

    @Override
    public void unLock() {
        synchronized (this){
            if (currentThread == currentThread()){
                this.locked = false;
                Optional.of(currentThread().getName()+"释放了锁")
                        .ifPresent(System.out::println);
                this.notifyAll();
            }
        }
    }

    @Override
    public List<Thread> getBlockedThreads() {
        //返回不可变的list
        return Collections.unmodifiableList(blockedList);
    }
}
package com.ibfbc.concurrency;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class BooleanLockTest {
    private final Lock lock = new BooleanLock();

    public void syncMethod() {
        try {
            lock.lock(1000);
            System.out.println(Thread.currentThread()+"得到了锁");
            TimeUnit.SECONDS.sleep(1);
        }catch (InterruptedException | TimeoutException e){
            e.printStackTrace();
        } finally {
            lock.unLock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        BooleanLockTest booleanLockTest = new BooleanLockTest();
//        IntStream.range(0,10).mapToObj(i-> new Thread(booleanLockTest::syncMethod,"T1"))
//                .forEach(Thread::start);
        new Thread(booleanLockTest::syncMethod,"t1").start();
        Thread t2 = new Thread(booleanLockTest::syncMethod,"T2");
        t2.start();
        TimeUnit.MILLISECONDS.sleep(10);

    }
}

测试超时任务,超时时间小于线程sleep时间,会抛出异常,具体测试可以自己进行。

打赏
本站所有资源均来源于网络,仅供学习使用,请支持正版!Java技术开源 » 自定义显示锁BooleanLock

评论 2

评论前必须登录!

 

  1. #1

    132

    并发编程网4年前 (2020-06-03)
  2. #2

    132

    并发编程网4年前 (2020-06-03)

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册