应用场景
需要开启多个线程,之后每个线程争抢锁,获取倒计时秒数权限,从而轮流打印倒计时
代码实现
public class ThreadSyncCountDown {
Integer seconds = 20;
Integer lock = new Integer(1);
public static void main(String[] args) {
// 开启3个线程,同步输出倒计时20s,
ThreadSyncCountDown t = new ThreadSyncCountDown();
t.threadMethod(3);
}
// count 线程数量,seconds倒计时秒数
public void threadMethod(int count) {
// 遍历线程
for (int i = 0; i < count; i++) {
// lambda 表达式实现函数式接口
new Thread(() -> {
while (seconds >= 0) {
countDown();
}
}).start();
}
}
public void countDown() {
synchronized (lock) {
if (seconds < 0)
return;
// 格式化时间输出
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(String.format("线程:%s,倒计时:%d,当前时间:%s", Thread.currentThread().getId(), seconds--, sf.format(new Date())));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.notifyAll();
}
System.out.println();
}
}
结果展示
注意细节
上述代码中原本synchronized(){} 代码块参数是需要倒计时的变量seconds,但是由于java装箱拆箱机制seconds–实际上是seconds = new Integer(seconds–),由于锁对象改变了,因此会报错如下:java.lang.IllegalMonitorStateException
所以针对于需要上锁的代码块,可以通过新定义一个不会改变的Integer lock = new Integer(1) 对象,或者直接用Object lock = new Object();这样就可以对代码块成功上锁,并且此处为了方便看到lock.notifyAll() 的效果。在上锁代码块执行完成后,通过降低当前线程的争抢锁能力,加了System.out.println();这行代码。