【问题标题】:Difference results for the same program [closed]同一程序的差异结果[关闭]
【发布时间】:2013-09-04 13:54:14
【问题描述】:
public class suspendCheck extends Thread{

    int t ;

    public static void main(String args[]) throws InterruptedException {
        suspendCheck as = new suspendCheck();

        Thread t2 = new Thread(as);
        t2.start();
        Thread t3 = new Thread(as);
        t3.start(); }

    public void run(){
        if(t==0){
        System.out.println("JAVA Develper");
        t= ++t;
        }
        else{

            System.out.println("JAVA Test");
            }

        }
}

多次运行此程序后存在差异和差异:

通常:

JAVA Develper
JAVA Develper

偶尔:

JAVA Develper
JAVA Test

我对此感到震惊。我哪里做错了?

【问题讨论】:

  • 欢迎来到线程同步的世界。
  • 是的,可以接受。这里唯一可怕的是你试图在不知道它们的限制的情况下使用线程。在这里责备 Java 是不对的。
  • 我只是不明白为什么人们给这个问题-1,他只是没有多线程经验

标签: java


【解决方案1】:

是的,这是可以接受的。这里唯一可怕的是你试图使用线程却不知道它们的局限性

你可以用一个线程轻松地做到这一点。你可以在这里走安全的道路。

线程不保证任何关于优化和排序的事情。如果您真的希望您的 int 正确更改,请将其设为 volatile 和/或使用 AtomicInteger。如果您想要更好的控制,请使用锁和/或synchronized 块。

在这种情况下,只需将 t 声明为 volatile 并围绕对 t 或 AtomicInteger 的访问进行同步,并使用该类的方法访问 t

为了将来参考,在不阅读所有相关警告的情况下尝试此类操作可能会导致死亡、窒息、寒战、发烧、溺水、感染、恶心和the inability to control highly expensive machinery

【讨论】:

  • ++t 不是原子的,所以这里的 volatile 不够(假设 OP 希望第一个 println 只打印一次)。而对于 AtomicInteger,他将需要一个 CAS 并避免他目前正在使用的 check-then-act...
  • +1 如果您想要特定的订单,请使用一个线程。它会更简单,而且通常也会更快。
  • @assylias t = ++t 更加困惑 ;)
  • @PeterLawrey 我什至没有注意到!
  • 提醒一下,最后的链接很适合阅读线程恐怖故事。
【解决方案2】:

我只是想添加你应该在比赛条件下阅读的六分之一答案:

并解释您在代码中所做的是让多个线程尝试获取整数并以其中一个线程可能会在另一个线程正在获取整数时更改它并因此覆盖给定值的方式进行更改由第一个线程。这就是你得到这种行为的原因

Java 中的竞争条件是一种并发错误或问题,它是 在您的程序中引入,因为您的程序的并行执行 由多个线程同时进行,由于Java是多线程的 编程语言,因此在 Java 中竞争条件的风险更高 这需要清楚地了解导致竞态条件的原因和 如何避免这种情况。

【讨论】:

  • 不鼓励链接到没有摘要的外部站点。我鼓励您添加关于一般竞争条件如何发生的摘要。
  • @hexafraction 可以,请稍等
  • 好的,没问题。我只是提供一个建议。
【解决方案3】:

您无法保证线程的执行顺序。当您在线程上调用start() 方法时,现在由线程调度程序决定执行顺序应该是什么

t1.start();
t2.start();

这并不意味着t1 肯定会在t2 之前运行。在您的示例中,您没有同步方法,两个线程可能同时运行,或者当一个线程到达第 4 行时,另一个线程可能已经完成执行。

 public void run(){
        if(t==0){
        System.out.println("JAVA Develper");
        t= ++t;    //Line 4
        }
        else{

            System.out.println("JAVA Test");
            }

        }

同步方法将为线程提供对象锁定。没有其他线程具有与可运行对象相同的对象,将能够同时访问同步块或方法。

 synchronized public void run()

【讨论】:

    【解决方案4】:

    如果事情需要并行而不是串行发生,您应该使用线程。除非您显式同步,否则会破坏线程的概念,否则事情将以未定义的顺序发生。

    理解线程并使其完全正确对于几乎任何语言来说都是至关重要的,也是最困难的事情。

    我建议阅读 joshua bloch 的 java concurrency in practice,了解使用线程时有多少陷阱,更重要的是,共享状态。

    【讨论】:

    • Java 并发实践的作者是 Brian Goetz(Joshua Bloch 是特约作者)
    猜你喜欢
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 2016-09-29
    • 1970-01-01
    相关资源
    最近更新 更多