简体   繁体   中英

Thread join() does not wait

I'm trying to learn about threads and I do not understand the join() method.

I have a Thread (ThreadAdd.java) which adds 1 to a static 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++;

    }

}

In my main method I launch 2 threads :

 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);

}

I do not understand why most of the time the result is 2 but sometimes it returns 1.

The reason why you sometimes see 1 is not because join() fails to wait for the thread to finish, but because both threads tried to modify the value concurrently. When this happens, you may see unexpected results: for example, when both threads try to increment count which is zero, they both could read zero, then add 1 to it, and store the result. Both of them will store the same exact result, ie 1, so that's what you are going to see no matter how long you wait.

To fix this problem, add synchronized around the increment, or use 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();
}

Because you're not synchronizing the increment of the integer count . The two threads may interleave while incrementing the variable.

See http://docs.oracle.com/javase/tutorial/essential/concurrency/interfere.html for an explanation. The example in the link is similar to your example and a solution provided to avoid this thread interference is to use atomic variables like java.util.concurrent.atomic.AtomicInteger .

The join method is not the real issue here. The problem is that your counter is not prepared for interthread synchronization, which may lead to each thread observing a different value in count .

It is highly recommended that you study some topics of concurrent programming, including how it is handled in Java.

Your count variable isn't volatile , and so there's no requirement for threads to check its value each time, and occasionally instruction ordering will cause errors like that.

In fact, though, since count++ is syntactic sugar for count = count + 1 , even making the variable volatile won't ensure that you don't have the problem, since there's a race condition between the read and the subsequent write.

To make code like this safe, use an AtomicInteger instead.

This has nothing to do with the join . The thread that waits by using join() is your main thread. The two other threads are not waiting for anything. And the join is not causing them to do anything differently.

And as the other answers said, the two threads are concurrently writing to the same variable, and therefore you get the result you see.

Perhaps you were expecting the join() to delay one of the threads so that it doesn't work concurrently with the other, but that's not how it works. The only thread that is delayed is the caller of join() , not the target thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM