java - 困惑的java ThreadPool和ReentrantLock

标签 java multithreading reentrantlock

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

相关文章:

用于过滤用户输入内容的Java库?

java - 如何在java中动态调整缓存线程池的大小

python - 线程处理时未执行的函数

java - 如果 Java 线程已经被该线程占用,为什么还必须重新进入该锁?

Java在不同线程上锁定和解锁

java - 在另一个类实例中获取一个类实例的变量值

Java - 从套接字 channel 读取

java - 尝试获取空索引时出现 IndexOutOfBoundsException : index: 1, size: 1 错误

java - 线程 Java 中断

java - ReentrantLock.lock() 不会阻塞其他线程