我得到固定数量的两个线程,然后提交了100个任务,其中我
使用了锁并故意将其解锁,此代码的运行结果是
从1到99排序数字,这让我很困惑:
1)是否是因为线程被复用,使得同一个线程可以多次获取?
2)如果是这样,锁不会阻塞线程,它仍然可以重用吗?锁保护的只是其范围内的线路。
请纠正我。
public class LockTest {
public static volatile int a = 1;
static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
for (int k = 0; k < 100; k++) {
executorService.submit(new Runnable() {
@Override
public void run() {
lock.lock();
System.out.println(a++);
}
});
}
executorService.shutdown();
}
}
最佳答案
如果您以这种方式修改代码,您将获得自己回答问题所需的所有信息:
public static void main(String[] args) {
ExecutorService executorService = newFixedThreadPool(2);
for (int k = 0; k < 100; k++) {
executorService.submit(() -> {
lock.lock();
System.out.println(currentThread().getId() +
" hold count: " + lock.getHoldCount());
System.out.println("a = " + a++);
});
}
executorService.shutdown();
}
输出示例
12 hold count: 1
a = 1
12 hold count: 2
a = 2
12 hold count: 3
a = 3
...
12 hold count: 98
a = 98
12 hold count: 99
a = 99
如您所见:
- 您想要输出
100
个数字,但只输出99
。 - 输出显示只有一个线程正在工作,因为您永远不会释放第一个线程获得的锁。第二个线程等待获取锁。
- 因为您使用了
ReentrantLock
,第一个获得锁的线程可能会继续工作,因为他已经拥有了锁。 - JVM 永远不会关闭,因为第一个线程永远不会释放锁,因此第二个线程将永远等待。
回答 PO 在评论中提出的问题
这是可以预测的:CachedThreadPool
将根据需要动态创建新的线程
。发生的情况是:
- 第一个线程将永远获得锁(因为它永远不会释放它)。它将尽快处理提交的任务。
- 当第一个线程正在处理时,
CachedThreadPool
将创建新线程来执行已提交但尚未处理的剩余任务。 - 根据获得锁的第一个线程的速度,处理尚未调度到其他线程的已提交任务,您最终将得到许多线程,永远等待。
关于java - 困惑的java ThreadPool和ReentrantLock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43535080/