synchronized问题演示
public class SynchronizedProblem {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread("t1"){
@Override
public void run() {
SynchronizedProblem.run();
}
};
t1.start();
Thread.sleep(1000);
// 开启一个线程去执行run方法,此时肯定会block住,因为t1没有释放锁,一直在运行
Thread t2 = new Thread("t2"){
@Override
public void run() {
SynchronizedProblem.run();
}
};
t2.start();
//假设等了2秒,t1还没有执行结束,没释放锁,t2还没有抢到执行权
// 就打断一下t2,不再进行抢锁,但是interrupt只能种下一个标志而已,无法让t2返回,不再去抢锁
t2.interrupt();
System.out.println(t2.isInterrupted());
}
private synchronized static void run(){
System.out.println(Thread.currentThread().getName() + " is running .....");
// 模拟线程一直没有释放锁
while (true){
}
}
}
2 解决问题
- 接口中定义的第二个方法就来解决这个问题
@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 synchronized void lock(long mills) throws InterruptedException, TimeOutException {
if (mills <= 0) {
log.error("mills => [{}] can not <= 0", mills);
throw new IllegalArgumentException();
}
long hasRemaining = mills;
// 当前线程,抢锁结束的时间
long endTime = System.currentTimeMillis() + hasRemaining;
while (!enableLock) {
if (hasRemaining <= 0) {
// 说明已经超时
throw new TimeOutException("Time out");
}
// 表示锁已经被其他线程拿走,进入等待,
this.wait(mills);
// 当这个线程被唤醒的时候,计算一下是否超时, hasRemaining <=0 说明超时
hasRemaining = endTime - System.currentTimeMillis();
}
// 表示锁已经被释放,可以获取锁
// 当前线程拿到锁可以执行,从blockThread移除
blockThread.remove(Thread.currentThread());
// enableLock set false,其他线程不可再持有该锁
this.enableLock = Boolean.FALSE;
// 记录抢到锁的线程
currentThread = Thread.currentThread();
}
@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();
}
}
测试
import lombok.extern.slf4j.Slf4j;
import java.util.stream.Stream;
@Slf4j
public class LockTest2 {
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(10L);
log.info("{} have the lock", Thread.currentThread().getName());
excute();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Lock.TimeOutException e) {
log.error("{} get the lock time out ",Thread.currentThread().getName());
} 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.LockTest2 - T1 have the lock
[T1] INFO study.wyy.concurrency.thread.lock.LockTest2 - T1 is excute start.....
[T3] ERROR study.wyy.concurrency.thread.lock.LockTest2 - T3 get the lock time out
[T2] ERROR study.wyy.concurrency.thread.lock.LockTest2 - T2 get the lock time out
[T4] ERROR study.wyy.concurrency.thread.lock.LockTest2 - T4 get the lock time out
t1 先抢到执行权,设置了抢锁的超时时间为10ms,而t1执行完需要10s,所以其他的三个线程肯定会抢锁
超时,不会再抢锁执行了
本文通过演示Java中synchronized关键字导致的线程阻塞问题,深入探讨了自定义锁机制——BooleanLock的实现原理及应用。通过对比synchronized的局限性,介绍了如何使用BooleanLock解决线程竞争与超时问题。
1280

被折叠的 条评论
为什么被折叠?



