我得到两个线程的固定数量,然后提交了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
将根据需要动态创建新的Threads
。发生的是:第一个线程将永远获得该锁(因为它永远不会释放它)。它将尽快处理提交的任务。
当第一个线程正在处理时,
CachedThreadPool
将创建新线程以执行已提交但尚未处理的其余任务。根据获得锁定的第一个线程的速度,处理尚未调度到其他线程的已提交任务,您将最终拥有许多线程,并永远等待。
关于java - 困惑的Java ThreadPool和ReentrantLock,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43535080/