JAVA多线程——自定义显示锁BooleanLock

Java基础

浏览数:126

2019-8-20

AD:资源代下载服务

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

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

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

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

Lock接口

package Lock.BooleanLock;

import java.util.List;
import java.util.concurrent.TimeoutException;

public interface Lock {
    //上锁     void lock() throws InterruptedException;
    //带超时功能的锁     void lock(long mills) throws InterruptedException, TimeoutException;
    //解锁     void unLock();
    //获取当前哪些进程被阻塞     List<Thread> getBlockedThreads();
}

BooleanLock实现

package Lock.BooleanLock;

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 Lock.BooleanLock;
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时间,会抛出异常,具体测试可以自己进行。

作者:不减商山(作者)