当前位置: 首页 > 知识库问答 >
问题:

为什么Java多线程代码会死锁

蔚学真
2023-03-14

此问题的完整代码可在此处获得:https://github.com/NACHC-CAD/thread-tool

下面显示的代码似乎一直运行到完成,但从未逃脱此处显示的while循环。

    while (this.active.size() > 0) {
        // System.out.println("here");
    }

如果我取消注释//系统。出来println(“此处”) 它确实运行到完成。如果我加上一秒钟的睡眠,它也会运行到完成。

更大的问题是,如果我尝试在实际应用程序中使用此代码,代码会运行一段时间,然后似乎死锁(即代码只是停止运行)。

我需要做什么来解决这个问题?

package org.nachc.tools.threadtool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.nachc.tools.threadtool.runnableiter.ThreadToolUser;
import org.nachc.tools.threadtool.worker.ThreadToolWorker;
import org.nachc.tools.threadtool.worker.ThreadToolWorkerRunnable;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ThreadRunner {

    private int numberOfThreadsPerWorker;

    private int numberOfRunnablesPerWorker;

    private int numberOfWorkers;

    private ThreadToolUser runnableIter;

    private List<ThreadToolWorker> active = new ArrayList<ThreadToolWorker>();

    private Object lock = new Object();

    private ThreadPoolExecutor executor;

    public ThreadRunner(int numberOfThreadsPerWorker, int numberOfRunnablesPerWorker, int numberOfWorkers, ThreadToolUser runnableIter) {
        this.numberOfThreadsPerWorker = numberOfThreadsPerWorker;
        this.numberOfRunnablesPerWorker = numberOfRunnablesPerWorker;
        this.numberOfWorkers = numberOfWorkers;
        this.runnableIter = runnableIter;
        this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(numberOfWorkers);
    }

    public void exec() {
        synchronized (lock) {
            addWorkers();
        }
        while (this.active.size() > 0) {
            // System.out.println("here");
        }
        log.info("SHUTTING DOWN----------------");
        executor.shutdown();
        try {
            executor.awaitTermination(1000, TimeUnit.HOURS);
        } catch (Exception exp) {
            throw (new RuntimeException(exp));
        }
    }

    private void addWorkers() {
        log.info("start addWorkers");
        while (runnableIter.hasNext() && active.size() < numberOfWorkers) {
            ThreadToolWorker worker = getNextWorker();
            if (worker == null) {
                break;
            } else {
                this.active.add(worker);
            }
        }
        log.info("done addWorkers");
    }

    private ThreadToolWorker getNextWorker() {
        synchronized (lock) {
            log.info("start next worker");
            if (runnableIter.hasNext() == false) {
                return null;
            }
            List<Runnable> runnableList = new ArrayList<Runnable>();
            while (runnableList.size() < numberOfRunnablesPerWorker && runnableIter.hasNext()) {
                runnableList.add(runnableIter.getNext());
            }
            ThreadToolWorker worker = new ThreadToolWorker(runnableList, numberOfThreadsPerWorker, this);
            ThreadToolWorkerRunnable runnable = new ThreadToolWorkerRunnable(worker);
            this.executor.execute(runnable);
            log.info("done next worker");
            return worker;
        }
    }

    public void done(ThreadToolWorker worker) {
        synchronized (lock) {
            log.info("start done");
            this.active.remove(worker);
            if (active.size() > 0) {
                addWorkers();
            }
            log.info("done done");
        }
    }

    public void logActive() {
        synchronized (lock) {
            log.info("------------");
            log.info("active:  " + active.size());
            log.info("waiting: " + runnableIter.waiting());
            log.info("------------");
        }
    }

}

共有1个答案

潘宸
2023-03-14

您的循环访问this.active.size()而没有任何同步。Java的内存可见性规则不保证当(如果有的话)一个查看共享变量的线程将看到其他线程所做的更改,如果正在查找的线程不使用某种形式的同步与其他线程。

如果要轮询活动列表的状态,请考虑执行以下操作:

while (true) {
    synchronized(lock) {
        if (this.active.size() <= 0) break;
    }
    try {
        Thread.sleep(1000);
    }
    catch (InterruptedException ex) {
        ex.printStackTrace();
    }
}

sleep()调用为其他线程提供了运行的机会。如果没有睡眠,运行这个循环的线程将使用100%的CPU,这可能对应用程序的性能有害。

但有比投票更好的选择。您可以等待活动列表变为空。

synchronized(lock) {
    while (this.active.size() > 0) {
        lock.wait();
    }
}

wait()调用暂时释放,然后等待另一个线程通知()锁,最后在返回前重新锁定锁:

public void done(ThreadToolWorker worker) {
    synchronized (lock) {
        log.info("start done");
        this.active.remove(worker);
        if (active.size() > 0) {
            addWorkers();
        }
        else {
            lock.notifyAll();
        }
        log.info("done done");
    }
}

 类似资料:
  • 在执行程序时,为了提供性能,处理器和编译器常常会对指令进行重排序,但是不能随意重排序,不是你想怎么排序就怎么排序,它需要满足以下两个条件: 在单线程环境下不能改变程序运行的结果; 存在数据依赖关系的不允许重排序 需要注意的是:重排序不会影响单线程环境的执行结果,但是会破坏多线程的执行语义。

  • 我正在http://www.python-course.eu/threads.php的帮助下学习python线程处理。这段代码的解释让我很困惑: 代码: 读取num_thread的值 一个新的int实例将增加或减少1(我认为一个新的int对象将被创建) 将新值分配给num_threads 像这样的错误发生在增量赋值的情况下: 第一个线程读取变量num_threads,它的值仍然是0。令人困惑的是:

  • 主要内容:1 什么是Java多线程,2 Java多线程的优点,3 进程与线程区别,4 Java Thread类,5 Java Thread类的方法1 什么是Java多线程 Java 多线程指的是同时执行多个线程的处理。 线程是轻量级子进程,是最小的处理单元。多处理和多线程都用于实现多任务。 但是,我们使用多线程而不是多进程,因为线程使用共享内存区域。它们不分配单独的内存区域,因此节省了内存,并且线程之间的上下文切换比进程花费的时间更少。 线程是轻量级子进程,是最小的处理单元。这是一条单独的执行路

  • 问题内容: 为什么在调用execute方法时将未处理的异常重新抛出在worker中?结果,将在下一次执行时创建新线程,以最大化线程数 问题答案: 为什么当RuntimeException发生时,java ThreadPoolExecutor杀死线程? 我只能猜测, 直接进行线程调用而不将其包装在a中的原因是,这样,即使您不在乎结果,也不会招致该线程的开销。 __ 如果您的线程抛出,这是很罕见的事情

  • 我试图通过拆分列表来检查元素是否在字符串中: `公共类ParallelSearchComment扩展了RecursiveTask{private static final long serialVersionUID=1L; `

  • 死锁描述了另外两个线程因为永远等待对方而被阻塞的情况。当死锁发生时,程序永远挂起,你唯一能做的就是杀死程序。 为什么在下面给出的示例生产者-消费者问题中没有发生死锁: 我想知道为什么当同步对象正在等待其他线程释放锁时,在同步块中调用等待方法不会导致死锁?