Each thread will start, and each thread will run to completion.
Within each thread, things will happen in a predictable order. But the actions of different threads can mix together in unpredictable ways. If you run the program multiple times, or on multiple machines, you may see different output. Even if you don’t see different output, you need to realize that the behavior you see is not guaranteed. Sometimes a little change in the way the program is run will cause a difference to emerge. Just for fun we bumped up the loop code so that each run() method ran the for loop 400 times rather than 3, and eventually we did start to see some wobbling:
public void run() {
for (int x = 1; x <= 400; x++) {
System.out.println("Run by "
+ Thread.currentThread().getName()
+ ", x is " + x);
}
}
Running the preceding code, with each thread executing its run loop 400 times, started out fine but then became nonlinear. Here’s just a snip from the command-line output of running that code:
Run by Rocky, x is 345
Run by Triple H, x is 313
Run by Cena, x is 341
Run by Triple H, x is 314
Run by Cena, x is 342
Run by Triple H, x is 315
Run by Rocky, x is 346
Run by Cena, x is 343
Run by Rocky, x is 347
Run by Cena, x is 344
And so on…
Notice that there’s not really any clear pattern here. If we look at only the output from Rocky, we see the numbers increasing one at a time, as expected:
Run by Rocky, x is 345
Run by Rocky, x is 346
Run by Rocky, x is 347
And similarly if we look only at the output from Cena, or Triple H. Each one individually is behaving in a nice orderly manner. But together, it is utter chaos! In the fragment above we see Rocky, then Cena, then Triple H (in the same order we originally started the threads), but then Cena moves in when it was Rocky’s turn. And then Triple H and Cena trade back and forth for a while until finally Rocky gets another chance. They jump around like this for a while after this. Eventually (after the part shown above) Rocky finishes, then Triple H, and finally Cena finishes with a long sequence of output. So even though Triple H was started third, he actually completed second. And if we run it again, we’ll get a different result.
Why?
Because it’s up to the scheduler, and we don’t control the scheduler! Which brings up another key point to remember: Just because a series of threads are started in a particular order doesn’t mean they’ll run in that order. For any group of started threads, order is not guaranteed by the scheduler. And duration is not guaranteed. You don’t know, for example, if one thread will run to completion before the others have a chance to get in or whether they’ll all take turns nicely, or whether they’ll do a combination of both.
A thread is no longer a thread when its run() method completes execution.
When a thread completes its run() method, the thread ceases to be a thread of execution. The stack for that thread dissolves, and the thread is considered dead. Not dead and gone, but, just dead. It’s still a Thread object, just not a thread of execution. So if you’ve got a reference to a Thread instance, then even when that Thread instance is no longer a thread of execution, you can still call methods on the Thread instance, just like any other Java object. What you can’t do, though, is call start() again.
Once a thread has been started, it can never be started again.
If you have a reference to a Thread, and you call start(), it’s started. If you call start() a second time, it will cause an exception (an IllegalThreadStateException, which is a kind of RuntimeException, but you don’t need to worry about catching it). This happens whether or not the run() method has completed from the first start() call. Only a new thread can be started, and then only once. A runnable thread or a dead thread cannot be restarted.
Within each thread, things will happen in a predictable order. But the actions of different threads can mix together in unpredictable ways. If you run the program multiple times, or on multiple machines, you may see different output. Even if you don’t see different output, you need to realize that the behavior you see is not guaranteed. Sometimes a little change in the way the program is run will cause a difference to emerge. Just for fun we bumped up the loop code so that each run() method ran the for loop 400 times rather than 3, and eventually we did start to see some wobbling:
public void run() {
for (int x = 1; x <= 400; x++) {
System.out.println("Run by "
+ Thread.currentThread().getName()
+ ", x is " + x);
}
}
Running the preceding code, with each thread executing its run loop 400 times, started out fine but then became nonlinear. Here’s just a snip from the command-line output of running that code:
Run by Rocky, x is 345
Run by Triple H, x is 313
Run by Cena, x is 341
Run by Triple H, x is 314
Run by Cena, x is 342
Run by Triple H, x is 315
Run by Rocky, x is 346
Run by Cena, x is 343
Run by Rocky, x is 347
Run by Cena, x is 344
And so on…
Notice that there’s not really any clear pattern here. If we look at only the output from Rocky, we see the numbers increasing one at a time, as expected:
Run by Rocky, x is 345
Run by Rocky, x is 346
Run by Rocky, x is 347
And similarly if we look only at the output from Cena, or Triple H. Each one individually is behaving in a nice orderly manner. But together, it is utter chaos! In the fragment above we see Rocky, then Cena, then Triple H (in the same order we originally started the threads), but then Cena moves in when it was Rocky’s turn. And then Triple H and Cena trade back and forth for a while until finally Rocky gets another chance. They jump around like this for a while after this. Eventually (after the part shown above) Rocky finishes, then Triple H, and finally Cena finishes with a long sequence of output. So even though Triple H was started third, he actually completed second. And if we run it again, we’ll get a different result.
Why?
Because it’s up to the scheduler, and we don’t control the scheduler! Which brings up another key point to remember: Just because a series of threads are started in a particular order doesn’t mean they’ll run in that order. For any group of started threads, order is not guaranteed by the scheduler. And duration is not guaranteed. You don’t know, for example, if one thread will run to completion before the others have a chance to get in or whether they’ll all take turns nicely, or whether they’ll do a combination of both.
A thread is no longer a thread when its run() method completes execution.
When a thread completes its run() method, the thread ceases to be a thread of execution. The stack for that thread dissolves, and the thread is considered dead. Not dead and gone, but, just dead. It’s still a Thread object, just not a thread of execution. So if you’ve got a reference to a Thread instance, then even when that Thread instance is no longer a thread of execution, you can still call methods on the Thread instance, just like any other Java object. What you can’t do, though, is call start() again.
Once a thread has been started, it can never be started again.
If you have a reference to a Thread, and you call start(), it’s started. If you call start() a second time, it will cause an exception (an IllegalThreadStateException, which is a kind of RuntimeException, but you don’t need to worry about catching it). This happens whether or not the run() method has completed from the first start() call. Only a new thread can be started, and then only once. A runnable thread or a dead thread cannot be restarted.
No comments:
Post a Comment