java多线程倒计时轮流输出synchronized Integer锁问题

java多线程倒计时轮流输出

应用场景

需要开启多个线程,之后每个线程争抢锁,获取倒计时秒数权限,从而轮流打印倒计时

代码实现

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();这行代码。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章