简体   繁体   English

Java多线程:为什么执行未在join()处停止?

[英]Java multithreading: why is execution not stopping at join()?

I have a module that deserializes a bunch of resources from files at start. 我有一个模块,它从一开始就反序列化文件中的大量资源。 Each takes time so I want to implement this in a multithreaded way so that each thread ingests a single resource. 每个线程都需要时间,因此我想以多线程的方式实现这一点,以便每个线程都摄取一个资源。 Following some examples I found on the web, I wrote this test class that represents the resource ingestion step of my main module. 遵循在网上找到的一些示例,我编写了这个测试类,该类代表主模块的资源提取步骤。

public class MultiThreadedResourceIngest {

    private static ResourceClass1 r1 = null;
    private static ResourceClass2 r2 = null;
    private static ResourceClass3 r3 = null;

    static class ResourceReader extends Thread {
        private Thread t = null;
        private int id = -1;
        private String path2read = null;

        ResourceReader( final int id, final String path2read){
           this.id = id;
           this.path2read = path2read;
        }

        public void run() {

           if (path2read != null && path2read.length() > 0)
           {
              switch (id) {
                 case 0:
                    r1 = new ResourceClass1(path2read);
                    break;
                 case 1:
                    r2 = new ResourceClass2(path2read);
                    break;
                 case 2:
                    r3 = new ResourceClass3(path2read);
                    break;
                 default:
                    break;
              }

           }
           log.info(String.format("Thread with id=%d and path=%s exiting", id, path2read));
        }

        public void start ()
        {
           if (t == null)
           {
              t = new Thread (this);
              t.start ();
           }
        }

    }

    public static void main(String[] args) {

        final String[] paths = new String[] {"path1", "path2", "path3"};

        log.info("STARTING MTHREADED READ");
        ArrayList<ResourceReader> rrs = new ArrayList<ResourceReader>();
        for (int i=0; i < paths.length; i++)
        {
           ResourceReader rr = new ResourceReader(i,paths[i]);
           rr.start();
           rrs.add(rr);
        }

        log.info("JOINING");
        for (ResourceReader rr: rrs)
        {
           try {
              rr.join();
           } catch (InterruptedException e) {
              // Thread interrupted
              e.printStackTrace();
           }
        }

        // Want to reach this point only when all resources are ingested
        //
        log.info("MTHREADED FINISHED");
    }

}

So here I have 3 resources and I want to get to the point marked // Want to reach this point... only after all the threads are done. 所以在这里,我有3个资源,并且我想到达标记为// Want to reach this point...仅在完成所有线程之后。 This is why I've implemented the join() loop, except it's not working as intended, ie the log looks like this: 这就是为什么我实现了join()循环的原因,除了它无法按预期运行外,即日志如下所示:

STARTING MTHREADED READ
Thread with id=0 and path=path1 exiting
JOINING
Thread with id=2 and path=path3 exiting
MTHREADED FINISHED
Thread with id=1 and path=path2 exiting

What do I need to change to wait until all resources are read before proceeding? 在继续阅读所有资源之前,我需要更改什么?

You declared class ResourceReader extends Thread , but you create another one and launch it inside start: 您声明了ResourceReader扩展Thread ,但是您创建了另一个类并在start内部启动它:

          t = new Thread (this);
          t.start ();

You should join on this thread, not on 您应该加入这个线程,而不是

          rr.join();

So just remove your start() method inside ResourceReader and everything will work. 因此,只需删除ResourceReader中的start()方法即可,一切都会正常进行。

You overrode the start method of thread and it doesn't call super.start(). 您覆盖了线程的start方法,它不调用super.start()。 All this start() does is create a new 2nd thread. start()所做的全部工作就是创建一个新的第二线程。 Remove that 2nd thread and don't override start(). 删除第二个线程,不要覆盖start()。

This way, the call to rr.start() will really start the rr thread, and it will end, and so will the join(). 这样,对rr.start()的调用将真正启动rr线程,并且将结束,而join()也将结束。

Too complicated! 太复杂! Why not just do this? 为什么不这样做呢?

static class ResourceReader implements Runnable {
    ...
    public void run() {
       ...
    }
}

public static void main(String[] args) {
    ...
    ArrayList<Thread> rrs = new ArrayList<>();
    for (int i=0; i < paths.length; i++)
    {
       Thread rr = new Thread(new ResourceReader(i,paths[i]));
       rr.start();
       rrs.add(rr);
    }
    ...
    for (Thread rr: rrs)
    {
       try {
          rr.join();
       } catch (InterruptedException e) {
          ...
       }
    }
    ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM