我得到两个线程的固定数量,然后提交了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/

10-09 00:05