10 自定义锁1

自定义显示锁

synchronized问题

被synchronized同步的线程,是不能被打断,一个线程一旦抢到synchronized同步锁,只要他不释放这个锁
其他线程就只能阻塞,调用者也无法打断这些在等待抢锁的线程
接下来将分两个笔记来解决这个问题:

  1. 如果自定义一个锁开始实现synchronized的功能
  2. 如何打断,并且设置超时时间,超时之后就不再进行抢锁

接口

import java.util.Collection;

public interface Lock {


    /**
     * 加锁,这个和synchronized的区别就是:
     *  
     * @throws InterruptedException
     */
    void lock() throws InterruptedException;

    /**
     *  加锁,指定允许等待时间,如果超时,还没有获得锁,则就抛出TimeOutException
     * @param mills
     * @throws InterruptedException
     * @throws TimeOutException
     */
    void lock(long mills) throws InterruptedException,TimeOutException;


    /**
     * 释放锁
     */
    void unLock();

    /**
     * 返回此时被该锁阻塞的线程
     * @return
     */
    Collection<Thread> getBlockThread();

    int getBlockSize();

    class TimeOutException extends Exception{
        public TimeOutException(String message) {
            super(message);
        }
    }
}

实现类

import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

@Slf4j
public class BooleanLock implements Lock{


    private Collection<Thread> blockThread = new ArrayList<>();
    /**
     * 默认值为True,尚未有其他线程持有该锁,能加锁,
     * 否则:该锁已经已经其他线程持有,不能加锁
     */
    private Boolean enableLock = Boolean.TRUE;
    @Override
    public synchronized void lock() throws InterruptedException {
        while(!enableLock){
            // 表示锁已经被其他线程拿走,进入等待,
            blockThread.add(Thread.currentThread());
            this.wait();

        }
        // 表示锁已经被释放,可以获取锁
        // 当前线程拿到锁可以执行,从blockThread移除
        blockThread.remove(Thread.currentThread());
        // enableLock set false,其他线程不可再持有该锁
        this.enableLock = Boolean.FALSE;
    }

    @Override
    public void lock(long mills) throws InterruptedException, TimeOutException {

    }

    @Override
    public synchronized void unLock() {
        // enableLock set true, 当前线程释放了锁,其他线程可进行抢夺该锁
        this.enableLock = Boolean.TRUE;
        log.info("{} release lock",Thread.currentThread().getName());
        // 别忘记唤起其他线程,进入runnable状态
        this.notifyAll();
    }

    @Override
    public Collection<Thread> getBlockThread() {
        // 设置返回的当前被锁住的线程是不能修改的,防止调用者修改该集合
        return Collections.unmodifiableCollection(blockThread);
    }

    @Override
    public int getBlockSize() {
        return blockThread.size();
    }
}

测试

**import lombok.extern.slf4j.Slf4j;

import java.util.stream.Stream;
@Slf4j
public class LockTest {
    public static void main(String[] args) throws InterruptedException {
        final Lock lock = new BooleanLock();
        // 创建四个线程
        Stream.of("T1","T2","T3","T4").forEach(t->{
            new Thread(t){
                @Override
                public void run() {
                    try {
                        lock.lock();
                        log.info("{} have the lock", Thread.currentThread().getName());
                        excute();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        lock.unLock();
                    }
                }
            }.start();
        });

    }


    /**
     * 模拟线程要执行的任务
     */
    private static void excute() throws InterruptedException {
        log.info("{} is excute start.....", Thread.currentThread().getName());
        Thread.sleep(10_000);
        log.info("{} is excute finsh.....", Thread.currentThread().getName());
    }
}

运行结果

[T1] INFO study.wyy.concurrency.thread.lock.LockTest - T1 have the lock
[T1] INFO study.wyy.concurrency.thread.lock.LockTest - T1 is excute .....
[T1] INFO study.wyy.concurrency.thread.lock.BooleanLock - T1 release lock
[T4] INFO study.wyy.concurrency.thread.lock.LockTest - T4 have the lock
[T4] INFO study.wyy.concurrency.thread.lock.LockTest - T4 is excute .....
[T4] INFO study.wyy.concurrency.thread.lock.BooleanLock - T4 release lock
[T2] INFO study.wyy.concurrency.thread.lock.LockTest - T2 have the lock
[T2] INFO study.wyy.concurrency.thread.lock.LockTest - T2 is excute .....
[T2] INFO study.wyy.concurrency.thread.lock.BooleanLock - T2 release lock
[T3] INFO study.wyy.concurrency.thread.lock.LockTest - T3 have the lock
[T3] INFO study.wyy.concurrency.thread.lock.LockTest - T3 is excute .....
[T3] INFO study.wyy.concurrency.thread.lock.BooleanLock - T3 release lock

可见只有线程释放了锁了,其他的线程才能抢到锁,执行

问题:

既然是API,就要限制用户的非法操作,比如,我们在main方法中释放锁

@Slf4j
public class LockTest {



    public static void main(String[] args) throws InterruptedException {
        final Lock lock = new BooleanLock();
        // 创建四个线程
        Stream.of("T1","T2","T3","T4").forEach(t->{
            new Thread(t){
                @Override
                public void run() {
                    try {
                        lock.lock();
                        log.info("{} have the lock", Thread.currentThread().getName());
                        excute();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        lock.unLock();
                    }
                }
            }.start();
        });
        Thread.sleep(100);
        lock.unLock();
    }


    /**
     * 模拟线程要执行的任务
     */
    private static void excute() throws InterruptedException {
        log.info("{} is excute start.....", Thread.currentThread().getName());
        Thread.sleep(10_000);
        log.info("{} is excute finsh.....", Thread.currentThread().getName());
    }
}

日志

[T1] INFO study.wyy.concurrency.thread.lock.LockTest - T1 have the lock
[T1] INFO study.wyy.concurrency.thread.lock.LockTest - T1 is excute start.....
[main] INFO study.wyy.concurrency.thread.lock.BooleanLock - main release lock
[T4] INFO study.wyy.concurrency.thread.lock.LockTest - T4 have the lock
[T4] INFO study.wyy.concurrency.thread.lock.LockTest - T4 is excute start.....

这个时候就会出现一个问题,当T1抢到锁执行了100ms的时候,main线程把锁给释放了,但是t1还没有执行完成,
锁锁就main线程释放了,导致其他的线程就可以抢锁运行,导致本来期望串行执行的变成了并发执行

解决问题

思路:

  • 记录是哪个线程获取到了锁
  • 释放的时候进行判断,由这个线程来释放锁
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

@Slf4j
public class BooleanLock implements Lock {
    private Collection<Thread> blockThread = new ArrayList<>();
    /**
     * 默认值为True,尚未有其他线程持有该锁,能加锁,
     * 否则:该锁已经已经其他线程持有,不能加锁
     */
    private Boolean enableLock = Boolean.TRUE;

    private Thread currentThread;

    @Override
    public synchronized void lock() throws InterruptedException {
        while (!enableLock) {
            // 表示锁已经被其他线程拿走,进入等待,
            blockThread.add(Thread.currentThread());
            this.wait();

        }
        // 表示锁已经被释放,可以获取锁
        // 当前线程拿到锁可以执行,从blockThread移除
        blockThread.remove(Thread.currentThread());
        // enableLock set false,其他线程不可再持有该锁
        this.enableLock = Boolean.FALSE;
        // 记录抢到锁的线程
        currentThread = Thread.currentThread();
    }

    @Override
    public void lock(long mills) throws InterruptedException, TimeOutException {

    }

    @Override
    public synchronized void unLock() {
        // 判断是不是抢到锁的线程,只有是持有该锁的线程才可以释放该锁
        if (currentThread != null && currentThread == Thread.currentThread()){
            // enableLock set true, 当前线程释放了锁,其他线程可进行抢夺该锁
            this.enableLock = Boolean.TRUE;
            log.info("{} release lock", Thread.currentThread().getName());
            // 别忘记唤起其他线程,进入runnable状态
            this.notifyAll();
        }
    }

    @Override
    public Collection<Thread> getBlockThread() {
        // 设置返回的当前被锁住的线程是不能修改的,防止调用者修改该集合
        return Collections.unmodifiableCollection(blockThread);
    }

    @Override
    public int getBlockSize() {
        return blockThread.size();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值