线程join()不等待

时间:2015-02-21 12:02:05

标签: java multithreading

我正在尝试了解线程,但我不理解join()方法。

我有一个Thread(ThreadAdd.java),它将1加到静态int。

public class ThreadAdd extends Thread{

public static int count;

    @Override
    public void run() {

        try {
            Thread.sleep(100);
        } catch (InterruptedException ex) {
            Logger.getLogger(ThreadAdd.class.getName()).log(Level.SEVERE, null, ex);
        }
        ThreadAdd.count++;

    }

}

在我的main方法中,我启动了2个主题:

 public static void main(String[] args) throws InterruptedException {

   ThreadAdd s1 = new ThreadAdd();
   ThreadAdd s2 = new ThreadAdd();
   s1.start();s2.start();
   s1.join();
   s2.join();
   System.out.println(ThreadAdd.count);

}

我不明白为什么大多数时候结果是2但有时会返回1.

5 个答案:

答案 0 :(得分:11)

您有时看到1的原因不是因为join()无法等待线程完成,而是因为两个线程都试图同时修改该值。发生这种情况时,您可能会看到意外的结果:例如,当两个线程都尝试递增count为零时,它们都可以读取零,然后向其添加1,并存储结果。它们都会存储相同的结果,即1,所以无论你等多久,你都会看到它。

要解决此问题,请在增量周围添加synchronized,或使用AtomicInteger

public static AtomicInteger count = new AtomicInteger(0);
@Override
public void run() {
    try {
        Thread.sleep(100);
    } catch (InterruptedException ex) {
        Logger.getLogger(ThreadAdd.class.getName()).log(Level.SEVERE, null, ex);
    }
    ThreadAdd.count.incrementAndGet();
}

答案 1 :(得分:4)

因为您没有同步整数count的增量。两个线程可以在递增变量时交错。

有关说明,请参阅http://docs.oracle.com/javase/tutorial/essential/concurrency/interfere.html。链接中的示例与您的示例类似,solution provided to avoid this thread interference是使用java.util.concurrent.atomic.AtomicInteger等原子变量。

答案 2 :(得分:4)

join方法不是真正的问题。问题是您的计数器没有为同步进行同步准备,这可能导致每个线程在count中观察到不同的值。

强烈建议您学习并发编程的一些主题,包括如何在Java中处理它。

答案 3 :(得分:2)

您的count变量不是volatile,因此每次都不需要线程检查其值,有时指令排序会导致这样的错误。

事实上,由于count++count = count + 1的语法糖,即使制作变量volatile也无法确保您没有问题,因为有一场比赛读取和后续写入之间的条件。

要使此类代码安全,请改用AtomicInteger

答案 4 :(得分:2)

这与join无关。使用join()等待的线程是您的线程。另外两个线程没有等待任何事情。并且join不会导致他们做任何不同的事情。

正如其他答案所说,两个线程同时写入同一个变量,因此你得到了你看到的结果。

也许您期望join()延迟其中一个主题,以便它不会与另一个主题同时工作,但这不是它的工作方式。唯一被延迟的线程是join()调用者,而不是目标线程。