如何创建并发运行的线程?

5

我希望有两个独立的线程分别运行不同类的实例,并且希望它们同时执行run命令。

我创建了一个示例类来演示我遇到的问题。一个选手向前数数,另一个向后数数。

public class testCount {

    public static void main(String args[]) {
        testCount countCompetition = new testCount();
        countCompetition.run();
    }

    public void run() {
        (new Thread(new racer1())).start();
        (new Thread(new racer2())).start();
    }

    public class racer1 implements Runnable {
        public void run() {
            for(int x = 0; x < 100; x++) {
                System.out.println(x);
            }
        }
    }
    public class racer2 implements Runnable {
        public void run() {
            for(int y = 100; y > 0; y--) {
                System.out.println(y);
            }
        }
    }
}

我的结果

1
2
... All the way to 100
100
100
99
... All the way back down
1

What I want

1
100
2
99
3
98

他们不需要那样轮流工作,但是他们需要同时工作,而不是一个接一个地工作。 如有提示、建议或代码片段,将不胜感激。

3个回答

7
我认为到目前为止,所有的答案都没有抓住重点。
你现有的逻辑确实可以使两个线程同时执行,但这并不明显,因为你的数字只到100,而且执行通常会停留在特定线程上超过1条指令,否则在当前执行线程之间切换会有大量的开销。在你的情况下,JVM决定执行你的第一个线程足够长的时间,以便它打印出100个数字,然后“上下文切换”到第二个线程。JVM可能选择以不同的方式执行线程,因此你看到的结果不能保证每次都相同。
如果你将数字增加到1000甚至更多,你将(可能)看到两个线程有所交错。你仍然会有大段时间其中一个线程连续打印出许多数字,因为JVM在切换之前执行一个线程一段时间比在每个指令之间切换更有效率。
添加Thread.sleep(1)不是一个好的解决方案,因为你正在添加一个不必要的延迟。当然,对于100个数字来说,这可能不明显,但对于10000个数字,你将有10秒的延迟。
你是否有任何理由需要它们互相交错的程度比它们已经做的更高?如果有,那么你简单的同时运行两个线程的模型是不够的。如果没有,那么就让JVM决定最佳的线程运行顺序(在你给出的简单示例中,这意味着它们大部分时间可能不会交错)。

1
我不知道为什么你的分析会被踩。我会用赞来纠正它。 - Martin James

1

在每个racer类中,在System.out.println()之后添加Thread.sleep(1);

例如,它会看起来像这样:

public class racer1 implements Runnable {
    public void run() {
        for(int x = 0; x < 100; x++) {
            System.out.println(x);
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

1
@James,不让它们等待/休眠的问题在于第一个线程将一直忙碌,因此第二个线程将无法分配任何CPU时间。 - ddmps
2
它也不能保证线程会一个接一个地运行。当它们完成任务时,您需要等待并相互通知。 - Edge
谢谢你的建议。幸运的是,线程交替对我项目的这部分并不是必要的。我会在将来牢记这点。 - James
不是关于交替线程,而是要避免使用Thread.sleep() - AllTooSir
2
@Andremoniy Thread.sleep从来都不是避免竞态条件的方法,更糟糕的是,如果它醒来时条件(其他线程的工作)还没有完成,它会消耗更多的CPU资源..却什么也没做。在你的情况下,完全有可能产生意外的结果(因为无序)。管理你的情况的最佳方法之一:http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html(比传统的基本`wait`/`notify`更好)。 - Mik378
显示剩余4条评论

-1

你需要编写一个基本的等待和通知系统。一个任务需要通知另一个任务他已经完成了工作。基本的思路可以从下面的代码中得到。创建两个任务,一个向前计数,一个向后计数。

Runnable task = new Runnable() {
  public void run() {
    System.out.println("woohooTwo");
    synchronized (t) {
      while (true) {
        System.out.println("---" + Thread.currentThread().getName() + "--" + t.i.getAndIncrement());
        t.notifyAll();

        try {
          Thread.sleep(1000);
          t.wait();
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }

    }
  }
};

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