2

我的任务是按以下顺序创建线程:如果A开始->开始B和C,如果B开始->开始D。并以相反的顺序销毁它们如果D然后B。如果B和C然后A。我希望你得到它。我设法做到了,但我想有更好的方法来做到这一点。你有什么建议吗?

在您发表评论后,我更改了我的代码,并且更加简单。但现在看起来很“愚蠢”。我想改变 if 语句和实现的核心,有什么建议吗?tnx 的建议,我正在和你一起学习。

这是我的新代码:

     import java.util.*;
class RobotController implements Runnable{
String name;

public void run() {
    Thread t = Thread.currentThread();
    System.out.println(t.getName() + " status = " + t.isAlive());
    System.out.println(t.getName() + " status = " + t.getState());

  }

public static void main(String args[]) throws InterruptedException{
    Thread thread_A = new Thread(new RobotController(), "Thread A");
    Thread thread_B = new Thread(new RobotController(), "Thread B");
    Thread thread_C = new Thread(new RobotController(), "Thread C");
    Thread thread_D = new Thread(new RobotController(), "Thread D");

    thread_A.start();
    thread_A.join();
    System.out.println(thread_A.getState());
    thread_B.start();
    thread_B.join();
    System.out.println(thread_B.getState());
    thread_C.start();
    thread_C.join();
    System.out.println(thread_C.getState());
    thread_D.start();
    System.out.println(thread_D.getState());


}

}
4

4 回答 4

3

您的代码中存在一些缺陷,有时会使其无法正常工作:

  1. 你打电话thread_A.start(),然后检查thread_A.isAlive()。现在如果在thread_A.isAlive()检查条件之前 thread_A 已经完成怎么办?thread_B并且thread_C永远不会开始。您的应用程序失败。
  2. 假设thread_A未完成且thread_A.isAlive()条件已通过,则Java 线程调度程序并不总是保证thread_B之前的启动。thread_C您的应用程序再次失败。
  3. 假设thread_B在之前开始thread_C,如果在之前thread_B完成,thread_B.isAlive()if条件失败并且thread_D永远不会开始。您的应用程序再次失败。

现在有一点需要思考:调用方法
后,不需要检查线程是否处于活动状态。join()这是不必要的运行时开销。

编辑
好的,这是代码的修改版本..我希望它能让你了解线程的动态:

class RobotController implements Runnable
{
    private final Object lock = new Object();
    private void notifyThread()
    {
        synchronized(lock)
        {
            lock.notify();
        }
    }
    public void run() 
    {
        synchronized(lock)
        {
            try
            {
                System.out.println(Thread.currentThread().getName() + " started");
                lock.wait();
                System.out.println(Thread.currentThread().getName()+ " stopped");
            }
            catch (InterruptedException ex)
            {
                ex.printStackTrace();
            }
        }
    }

    public static void main(String args[]) throws InterruptedException
    {
        RobotController rca = new RobotController();
        RobotController rcb = new RobotController();
        RobotController rcc = new RobotController();
        RobotController rcd = new RobotController();


        Thread thread_A = new Thread(rca,"Thread A");
        Thread thread_B = new Thread(rcb,"Thread B");
        Thread thread_C = new Thread(rcc,"Thread C");
        Thread thread_D = new Thread(rcd,"Thread D");

        thread_A.start();
        while (thread_A.getState() != Thread.State.WAITING)
        {
            Thread.sleep(100);
        }
        thread_B.start();
        thread_C.start();
        while (thread_B.getState() != Thread.State.WAITING && thread_C.getState() != Thread.State.WAITING)
        {
            Thread.sleep(100);
        }
        thread_D.start();
        while (thread_D.getState() != Thread.State.WAITING)
        {
            Thread.sleep(100);
        }
        rcd.notifyThread();
        thread_D.join();
        rcc.notifyThread();
        thread_C.join();
        rcb.notifyThread();
        thread_B.join();
        rca.notifyThread();
    }

}

这是输出:

Thread A started
Thread B started
Thread C started
Thread D started
Thread D stopped
Thread C stopped
Thread B stopped
Thread A stopped
于 2013-06-13T11:16:16.257 回答
2

在多线程中,除非公共数据由多个线程共享,否则不需要同步。在您的情况下,您希望以特定顺序启动和停止线程。为此,Thread 类中有 join 方法。链接显示了连接方法的良好示例。

于 2013-06-12T18:07:15.537 回答
0

synchronized (lock)在我看来,在你的 run 方法中使用来锁定你的对象是很奇怪的。原因是在每个Thread对象中都有不同的lock属性,属于每个对象。这意味着您正在尝试锁定不同的对象。实际上,这没有任何意义。

基本上,您应该应用的synchronized对象是任何共享对象。例如,您需要计算一些东西,然后创建一个类对象以在您的类中共享它。在这种情况下,它应该在被读取或写入时被锁定。

于 2013-06-12T18:11:13.773 回答
0

我想在这里强调两点:

  1. 在这里查看线程执行生命周期。它说,当调用 start() 方法时,线程进入可运行状态而不是运行状态。当线程进入运行状态时,这意味着 run() 方法正在被执行。CPU/OS 决定哪个线程应该从可运行线程转移到运行线程的优先级。例如,如果您为 4 个线程调用 start() 方法,则它们不必按特定顺序执行。(在我的电脑上多次运行同一个程序会给我不同的输出。

在您的情况下,执行条件 if(thread_A.isAlive()) 时,线程 A 可能未处于运行状态。因此,如果哪个不正确,控制将不会进入。为了纠正这种行为,在 main 中,应该实现一个 while 循环,该循环等待线程变为活动状态,依此类推。

2. 在您的程序中,您没有为线程分配名称,而是在 run() 方法中打印名称。在这种情况下,JVM 会按照线程的执行顺序为线程分配名称,例如第一个要执行的线程的名称为“Thread-0”,依此类推。因此,我们将无法确定哪个线程首先执行。使用 setName() 方法分配名称。

于 2013-06-13T09:42:46.123 回答