代码之家  ›  专栏  ›  技术社区  ›  Hadi

当ExecutorService执行线程时,Thread.join()不起作用

  •  2
  • Hadi  · 技术社区  · 6 年前

    public static void main(String[] args) {
            System.out.println("program started");
            ExecutorService executor = Executors.newCachedThreadPool();
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("thread finished");
                }
            });
            executor.execute(thread);
            try {
                thread.join();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("thread joined");
    
        }
    

    当我开始我的 如上图所示, thread.join() 螺纹 执行服务 同时也要等待线程完成。但我的代码不好用。有人能帮我吗?

    为什么我不使用 未来 而不是 螺纹 ?

    螺纹 螺纹 待完成。但是当我取消一个 未来 , future.get() 螺纹

    如果我的句子语法不正确,我要事先道歉。因为我英语说得不好。

    5 回复  |  直到 6 年前
        1
  •  14
  •   GhostCat    6 年前

    简单的回答是:不要那样做。

    execute() 线。它需要 运行任务 . 将线程对象传递给它并不重要,除了调用 run() 方法。

    整个要点 线程池 概念是你知道 尝试控制底层线程。等待池线程 . 线程池使线程保持在周围,因为建立线程是一个(相对)昂贵的操作。所以他们不会结束,但要活下去 其他 未来的工作。

    这里真正的答案是:要么不要使用executor服务,要么寻找一个可以使用这个概念的解决方案(不需要你去做一些低级的事情)。

    还有“真实”的答案:退后一步,告诉我们你打算用这种方式解决的“真实”问题。

        2
  •  8
  •   bowmore    6 年前

    注意 Executor.execute() Runnable . 以及 Thread 工具 ,所以它可以传递给 Executor Executors.newCachedThreadPool() 只是用那个 run() 螺纹 实例你通过。这个 它本身永远不会启动,因为执行器使用它在其线程池中内部管理的线程。

    解决方法很简单: 重播 ExecutorService ,使用其 submit(Runnable) Future<?> 作为返回值。打电话 get() 对未来的影响将与 Thread.join()

    对于如何使用 执行服务 你可以看看这里: http://tutorials.jenkov.com/java-util-concurrent/executorservice.html

        3
  •  3
  •   Erwin Bolwidt    6 年前

    当你使用 ExecutorService ,你应该通过一个 Runnable Thread 是一个 可运行 执行服务 .

    执行服务 submit ,它允许您等待 (或 Callable ,如果要返回结果)

    您可以将代码更改为:

    public static void main(String[] args) {
        System.out.println("program started");
        ExecutorService executor = Executors.newCachedThreadPool();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread finished");
            }
        };
        Future<?> future = executor.submit(runnable);
        try {
            future.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("waited for completion");
    }
    
        4
  •  1
  •   xingbin    6 年前

    Runnable 另一个线程的对象。这就是为什么 join 不会阻塞主线程。

    public static void main(String[] args) {
        System.out.println("program started");
        ExecutorService executor = Executors.newCachedThreadPool();
    
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread finished");
            }
        };
    
        executor.execute(runnable);
    
        try {
            Thread thread = new Thread(runnable);
            thread.join();  // the thread never start, so it will not block main thread
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("thread joined");
    }
    

    您可以尝试打印线程名称:

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread()); // Thread[pool-1-thread-1,5,main]
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread finished");
        }
    });
    executor.execute(thread);
    
    System.out.println(thread); // Thread[Thread-0,5,main]
    
        5
  •  1
  •   nits.kk    6 年前
    1. Executor.java(接口)有一个方法 execute(Runnable command) Executors.newCachedThreadPool() 执行(Runnable命令) 方法并执行 run() 方法。

    2. 您提供了一个线程实例(它实现了Runnable),因此内部线程(如第2点所述)调用run方法,但从不调用 start() 方法。 execute() 方法接受传递的实例,但 它只知道它是Runnable类型,不知道那个方法 开始() 存在 . 不知道它不能调用它。任何其他程序员都可以传递类的实例,如 class Task implements Runnable 也可能有类似的方法 invokeMeIAmImportantMethod() . 但遗嘱执行人知道的任何方法 public void run() 在可运行接口的契约中定义。

    3. 方法 join() 以前调用过线程实例 开始()

    A) 当我们使用了newCachedThreadPool()时,这意味着我们需要一个ThreadPool服务。这意味着线程池服务将阻塞线程并执行您的任务(或命令)。不需要启动线程来执行任务,也不需要启动separate线程池。这是一种混乱的逻辑。 所以要么移除Threadpool并启动线程,要么移除线程并依赖于Threadpool。

    B) 另外,我建议您使用调试。您可以调试并找到线程的状态(它应该是新的)。这将引导您进行更多的研究,最终您将看到ExecutorService execute()方法所期望的参数。