执行两个线程,它们互相等待,而主线程继续执行。

6

如何启动两个线程,其中线程1首先执行,当线程1结束时,线程2开始运行,同时主方法线程可以在不锁定其他两个线程的情况下继续工作?

我尝试使用join()但是必须从等待另一个线程的线程中调用它,没有办法像thread2.join(thread1)这样做; 如果我在main()内部调用join,则实际上停止了主线程的执行,而不仅仅是停止了线程2。

因此,我尝试使用ExecutorService,但同样存在问题。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Test
{
    public static void main(String args[]) throws InterruptedException
    {
        System.out.println(Thread.currentThread().getName() + " is Started");

        class TestThread extends Thread
        {
            String name;
            public TestThread(String name)
            {
                this.name = name;
            }

            @Override
            public void run()
            {
                try
                {
                    System.out.println(this + " is Started");
                    Thread.sleep(2000);
                    System.out.println(this + " is Completed");
                }
                catch (InterruptedException ex)  {  ex.printStackTrace(); }
            }

            @Override
            public String toString()  { return "Thread " + name; }
        }

        ExecutorService executor = Executors.newCachedThreadPool();
        executor.execute(new TestThread("1"));

        boolean finished = executor.awaitTermination(1, TimeUnit.HOURS);

        if(finished)
        {
           //I should execute thread 2 only after thread 1 has finished
            executor.execute(new TestThread("2"));
        }

        //I should arrive here while process 1 and 2 go on with their execution
        System.out.println("Hello");
    }
}

#编辑:为什么我需要这个:

我需要这个是因为Thread1将数据库表中的元素复制到另一个数据库中,Thread2必须复制引用从Thread1复制的表的链接表。 因此,只有当Thread1完成后,Thread2才能开始填充其链接表,否则数据库会给出完整性错误。 现在想象一下,我有几个线程具有不同的优先级,由于复杂的链接表,您就有了一个想法。


7
如果两个任务必须依次执行,为什么需要两个线程? - Tala
我在上面添加了一个“为什么需要这个”的说明,希望清楚明了。 - dendini
我觉得现在我表达得更清楚了 :) - dendini
8个回答

4
我相信你可能有些误解,因为这个必须能够工作,而且它确实可以工作:
new Thread() {
    @Override
    public void run() {
        TestThread t1= new TestThread("1");
        TestThread t2= new TestThread("2");
        try {
            t1.start();
            t1.join();
            t2.start();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}.start();

输出结果为:
main is Started
Hello
Thread 1 is Started
Thread 1 is Completed
Thread 2 is Started
Thread 2 is Completed

另一个选项就是扩展“线程1”的TestThread,以便在完成自己的工作后执行“线程2”的工作。类似于这样:

final TestThread t2= new TestThread("2");
TestThread t1= new TestThread("1") {
    @Override
    public void run() {
        super.run(); //finish t1 work
        t2.start();  // start t2 work
    }
};
t1.start();

1
确切地说,我希望主线程继续执行而不等待。 - dendini
好的,它可以工作了,撤销了负数。但我个人不会创建第三个线程来控制其他两个。 - Tala

4
第二个线程可以像这样自定义(以前一个线程为参数):
public static void main(String[] a) {
    Thread first = new Thread(new Runnable() {
        @Override
        public void run() {

        }
    });

    Thread second = new MyThread(first);
    first.start();
    second.start();

    //continue executing
}

public static class MyThread extends Thread {

    private Thread predecessor;

    public MyThread(Thread predecessor) {
        this.predecessor = predecessor;
    }

    public void run() {
        if (predecessor != null && predecessor.isAlive()) {
            try {
                predecessor.join();
            } catch (InterruptedException e) {}
        }
        //do your stuff
    }
}

以上代码无法正常工作,主程序在第一个程序运行完成之前就继续运行了。我认为第二个程序会锁定主程序直到第一个程序完成。 - dendini

3
您可以使用CountDownLatch:
在主线程中创建它,将其传递给两个线程,并在第一个线程退出时调用它的倒数计数,并等待在第二个线程开始时将其倒数计数。

1

为什么不让线程1启动线程2呢?

// in main
new Thread(new Runnable() {
    @Override public void run() {
        // do thread1 work
        new Thread(new Runnable() {
              @Override public void run() { /* do thread2 work */ }
        }).start();
    }
}).start();

然而,为什么你要这样做而不是让thread1完成100%的后台工作并不清楚。

也许这个显而易见的解决方案太过显而易见了——另一个帖子建议了它,但由于某些原因被踩了。这肯定是最简单的方法,比明确的信号建议要简单得多。 - Martin James

1
你可以使用SingleThreadExecutor来依次运行一个任务Java doc
这样,它会按顺序将您的任务排列,并在不阻塞主线程的情况下依次执行。

1
尝试这个,它会按预期工作。两个线程交替打印奇数和偶数,主线程尽快退出。
public class YoThreD {

    static boolean isThread1 = false;

    public static synchronized boolean isThread1() {
        return isThread1 = !isThread1;
    }

    public static void main(String args[]) {

        Runnable runnableObject = new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    for (int i = 1; i <= 100; i++) {
                        try {
                            if (Thread.currentThread().getName().equals("thread1")) {
                                if (isThread1()){
                                    System.out.println(Thread.currentThread().getName() + "    :   " + i);
                                }else{
                                    this.notify();
                                    this.wait();
                                }
                            } else {
                                if (!isThread1()){
                                    System.out.println(Thread.currentThread().getName() + "    :   " + i);
                                    this.notify();
                                    this.wait();
                                }
                                else{
                                }
                            }
                        } catch (Exception e) {
                        }
                    }
                }
            }
        };
        Thread thread1 = new Thread(runnableObject);
        thread1.setName("thread1");
        thread1.start();
        Thread thread2 = new Thread(runnableObject);
        thread2.setName("thread2");
        thread2.start();
        System.out.println(Thread.currentThread().getName() + "Main thread finished");
    }
}

0

您可以使用多种方式依次运行两个线程:

1. 通过使用join()方法。例如:
Thread t1=new Thread(new Runnable() {
    @Override
    public void run() {
        for (int i = 0; i < 4; i++) {
            System.out.println("A " + i);
        }
    }
});
Thread t2=new Thread(new Runnable() {
    @Override
    public void run() {
        for (int i = 0; i < 4; i++) {
            System.out.println("B " + i);
        }
    }
});
2. 通过使用wait()和notify()方法:例如。

`

{
public class NotiffyAllExample {

    int flag = 1;

    public static void main(String[] args) {

        NotiffyAllExample notiffyAllExample = new NotiffyAllExample();

        A1 a = new A1(notiffyAllExample);
        B1 b = new B1(notiffyAllExample);
        C1 c = new C1(notiffyAllExample);
        a.start();
        b.start();
    }
}

class A1 extends Thread {

    NotiffyAllExample notiffyAllExample;

    public A1(net.citigroup.mexico.pg.test.test.NotiffyAllExample notiffyAllExample) {
        this.notiffyAllExample = notiffyAllExample;
    }

    @Override
    public void run() {

        try {
            synchronized (notiffyAllExample) {

                for (int i = 0; i < 4; i++) {

                    while (notiffyAllExample.flag != 1) {
                        notiffyAllExample.wait();
                    }
                    System.out.print("A ");
                }
                notiffyAllExample.flag = 2;
                notiffyAllExample.notifyAll();
            }
        } catch (Exception e) {
            System.out.println("Exception 1 :" + e.getMessage());
        }

    }
}

class B1 extends Thread {

    NotiffyAllExample notiffyAllExample;

    public B1(NotiffyAllExample notiffyAllExample) {
        this.notiffyAllExample = notiffyAllExample;
    }

    @Override
    public void run() {
        try {
            synchronized (notiffyAllExample) {

                for (int i = 0; i < 4; i++) {

                    while (notiffyAllExample.flag != 2) {
                        notiffyAllExample.wait();
                    }
                    System.out.print("B ");
                }
                notiffyAllExample.flag = 1;
                notiffyAllExample.notifyAll();

            }
        } catch (Exception e) {
            System.out.println("Exception 2 :" + e.getMessage());
        }

    }
}
}

`


0

这可能是一个愚蠢的问题,但如果线程1完成后线程2应该执行...为什么不直接从线程1开始呢?

或者也许只需让线程1触发一个事件,主线程就可以响应并启动新线程。

我找到了this个例子,应该适合你。


这应该是一条注释,而不是一个答案。 - Petr
什么?这是实现OP想要的完全合理的方式。 - Martin James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接