Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 未在命令行应用程序中调用SwingWorker.process()_Java_Multithreading_Command Line_Deadlock_Swingworker - Fatal编程技术网

Java 未在命令行应用程序中调用SwingWorker.process()

Java 未在命令行应用程序中调用SwingWorker.process(),java,multithreading,command-line,deadlock,swingworker,Java,Multithreading,Command Line,Deadlock,Swingworker,我观察到调用SwingWorkers的命令行应用程序有一种奇怪的行为。代码是非最优的,因为它创建了很多线程池。但是,由于生成变量的控制,除最后一个池外,所有这些池都不执行任何代码。这意味着这些池中的线程不仅不参与锁竞争,还应该被垃圾收集并消失 下面是一个最简单的工作示例(没有使任何内容变得有用): package test; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.

我观察到调用SwingWorkers的命令行应用程序有一种奇怪的行为。代码是非最优的,因为它创建了很多线程池。但是,由于
生成
变量的控制,除最后一个池外,所有这些池都不执行任何代码。这意味着这些池中的线程不仅不参与锁竞争,还应该被垃圾收集并消失

下面是一个最简单的工作示例(没有使任何内容变得有用):

package test;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.SwingWorker;

public class Tester {

private final int threads;
private ExecutorService threadPool;
private final int size;
private long currGen;
private int left;
private int done;

public Tester(int size, int threads) {
    this.threads = threads;

    this.size = size;

    this.currGen = 0;

    this.left = size;
    this.done = 0;
}

private class TestWorker extends SwingWorker<Object, Object> {
    private final Tester tester;
    private final long generation;

    TestWorker(Tester tester, long generation) {
        this.tester = tester;
        this.generation = generation;
    }

    @Override
    protected Object doInBackground() throws Exception {
        while(this.tester.get(generation)) {
            Thread.sleep(1);
            publish(1);
        }

        return null;
    }

    @Override
    protected void process(List<Object> results) {
        for(Object n : results) {
            this.tester.put(generation);
        }
    }
}

public void run() {      
    this.currGen++;        
    this.left = size;
    this.done = 0;

    System.out.printf("Starting %d\n", currGen);

    this.threadPool = Executors.newFixedThreadPool(threads + 4);

    for (int threadId = 0; threadId < threads; threadId++) {
        threadPool.submit(new TestWorker(this, currGen));
    }
}

public synchronized boolean get(long generation) {        
    if (generation != currGen) {
        return false;
    }

    if (this.left == 0) {
        return false;
    }

    this.left--;

    return true;
}

public synchronized void put(long generation) {           
    if (generation != currGen) {
        return;
    }

    this.done++;

    if (this.done == this.size) {
        this.run();
    }
}
}
观察到的行为:输出包括启动1\n[…]启动1034\n之后,进程仍处于活动状态,但不再打印更多行。在死锁时刻,我的进程的线程数是31014。实验是在一台24芯的机器上进行的

预期行为:对于k=1,2,…,进程应保持从k\n开始打印。。。永久或抛出由创建的线程池过多导致的
OutOfMemoryError


给出的示例具有有限的调试功能。在某个时刻,我有更多的printf命令,它们意味着当前一代的所有创建线程都调用了它们的
publish()
方法,但EDT没有调用
process()
方法时会发生死锁。

与Holger讨论后,问题似乎是由创建多个线程池引起的:

在程序执行k轮后(即打印
开始k\n
),创建了大小为34的k个线程池。其中,除了执行上一代的
doInBackground()
方法的30个线程之外,所有线程都不执行任何代码,但仍在运行
。仍在执行代码的30个线程在
get()
put()
方法上同步,并陷入死锁,因为AWT eventdispatch线程出于某种原因不执行
publish()
方法。造成这种死锁的唯一原因是有许多线程被创建并运行(尽管它们中的大多数都不是活动线程,也没有参与竞争)


讨论后的共识似乎是:由于创建了太多线程,系统(Java外部)违反了一些约束,使JVM停止运行。

您期望什么?当
this.done==this.size
时,调用
run()
,将
done
设置为零。只有当
this.done>this.size
时,才会打印消息,但如果在达到该条件之前将
done
设置为零,则显然不可能达到该条件。我不确定您在重复创建新池时是否理解线程池的用途…但这段奇怪代码的用途仍然不清楚。您在创建新线程池之前打印“Start…”消息,因此每次看到该消息,您正在创建一个固定数量为15个线程的新线程池。因此,当您看到消息“Starting 2813”时,您已经创建了2813×15==42195个线程。你认为,你真的可以排除程序挂起和创建42195个线程之间的关系,所有线程都在同一个对象上重复调用
synchronized
方法?抱歉,如果这听起来太苛刻,但是一个问题的最低要求是描述预期的行为,不可能从你的程序中猜出意图,因为它根本没有任何意义。所有线程都在更改相同的变量,因此线程是否完成完全是随机的。由于每次完成都会触发另外15个线程的开始,所以您只需创建臭名昭著的fork bomb的一个变体。我通过发布另一个解释来反驳自己:您假设,当一个线程遇到
this.done==this.size
条件时,所有其他线程都已完成。这是错误的。将有一个线程遇到
get
中的最后一项。此时,没有其他线程遇到
left==0
。线程将发布最后一项。现在,有15个线程调用
get
,再加上EDT调用
put
来竞争锁。有些线程可能会成功并遇到
left==0
,但肯定不是全部。现在EDT遇到
get()
中的
this.done==this.size
,调用
run()
,启动15个新线程,并将非常
左侧的
变量重置为零,尚未完成的线程将在下一次
get
调用中读取该变量。他们都像新来的一样。直到遇到
get
中的最后一项,比赛再次开始。请注意,
synchronized
是“不公平的”。由于
发布
/
进程
关系,EDT最后尝试获取锁的几率更高,使更多池线程处于运行状态。您看错了方向。如果EDT停止调用
进程()。这意味着,一旦垃圾收集器回收了一些池,其他线程应该继续并最终进入等待状态,甚至终止(这可能取决于Java版本,池是否有这样的清理)。可能是EDT在尝试为新池创建更多线程时挂起。这将取决于系统,并且超出垃圾收集器的范围。我承认,我没有尝试过你的24核程序……我在第一篇文章中修改了代码,以保证在连续几代中创建的线程不会相互竞争。新代码运行了1034代,并出现死锁。您看到了为什么会出现死锁而不是异常的任何解释了吗?您仍然在创建新的线程池,即使您现在正在存储
    Tester tester = new Tester(30 * 400, 30);

    tester.run();