调用start和run后的线程变量

时间:2013-07-23 19:40:11

标签: java multithreading

我意识到这段代码:

public class TestThread3 extends Thread {

    private int i;
    public void run() {
         i++;
    }
    public static void main(String[] args) {
        TestThread3 a  = new TestThread3();
        a.run();
        System.out.println(a.i);
        a.start();
        System.out.println(a.i);
    }
}    

导致1 1打印出来...而且我没有得到它。我还没有找到有关如何解释这一点的信息。感谢。

3 个答案:

答案 0 :(得分:8)

  

导致1 1打印

因此,主线程直接通过调用a.run();方法调用第一个a.run()。这会将a.i增加为1.然后调用对a.start();的调用,实际上会调用新线程。但是,这需要花费时间,i++;操作很可能在System.out.println(...)调用之前尚未开始,因此a.i仍然只有1.即使i++ <在a运行{/ 1}之前,{> 1}线程中已完成<>> ,没有任何因素导致println字段在a.i线程和主线程。

如果你想等待生成的线程完成,那么你需要在调用a之前进行a.join();调用。 println方法确保在join()线程中完成的内存更新对于线程调用连接是可见的。然后主线程将看到a更新。您还可以使用i++代替包含AtomicInteger的{​​{1}}并提供内存同步。但是,如果没有int,执行增量的volatile int线程和join()之间仍存在争用条件。

a

答案 1 :(得分:0)

这种行为可以随时改变,因为当调用a.start()时,线程被安排进程,操作系统不会让它开始在CPU上执行。

一旦a.start()返回,你实际上有两个线程(一个用于main,另一个用于新线程),main仍然在运行。

预期结果只有在以下情况发生时才会出现,

时间

T1 main方法调用a.start()

T2 jvm / os调度线程执行

T3 a.start()返回,主线程获得上下文切换并暂停其他线程。

T4生成的线程获取执行上下文,并调用其run方法,该方法增加值

发生T5上下文切换,主线程恢复控制

T6主线程将打印2

Jatan

答案 2 :(得分:0)

这里有两个主要问题需要清理。我还建议您查看Gray的答案以获取更多技术信息。

**注意:这只是略微撇开表面,但大多数其他答案都认为我认为您还没有掌握这些计算机科学主题的背景知识。

首先,线程不保证执行顺序。通常,只有在异步工作(独立定时)时才应使用线程。对于这个例子,你有一个特定于时间的预期结果,因此可能应该避免使用线程。

然而,这不是你唯一的问题。

原样,您的代码也具有所谓的竞争条件。当两个不同的线程(或进程)有权读取/操作相同的数据时,就会出现竞争条件 - 在您的情况下,阅读i并通过i++递增。

例如,

想象一下,你和一个朋友都有一美元。冰淇淋男子一路开车,停在你面前。冰淇淋男子只剩下一个冰淇淋蛋筒。这可以通过以下几种方式实现:

  1. 你比朋友快,先买锥。
  2. 你比你朋友慢,他先买锥子。
  3. 你决定拆分冰淇淋甜筒,两者都要支付0.50美元。
  4. 当你们两个分心的时候,你们两个人打架,其他人可以买最后一个冰淇淋蛋筒。
  5. 要将其镜像回计算机,

    1. 即使在启动第二个线程后,您正在打印的主线程仍继续运行。 (线程链接到相同的进程,所以当main返回时,其他线程“死”。线程可能,即使它a.start()'ed,也没有完成或甚至没有机会一直跑!)
    2. 另一个线程在返回主线程之前运行并完成。
    3. 你轮流执行,每个人都可以做几行代码。外出来的确非同步。这很有可能发生。
    4. java应用程序进程丢失了CPU并且其他人可以运行(可能访问类似的共享信息。)
    5. TL; DR -

      如果你想确保执行顺序,那就不要使用线程。

      在某些情况下,沿途的某些点同步会很好。对于这些情况,您可以加入线程(等待一个线程在继续之前完成),或者使用Mutex或Semaphore锁定Race Condition(更高级的同步技术)。

      我建议在尝试与怪异的操作系统进行战斗之前先阅读这些主题。