I will give the best answer to a beginner and not exactly to solve the problem (that neither exists).
Introducing
First, your computer is not in trouble. Even if it were, it would not affect the program’s functioning in this way. The program would not even work.
Second, the chance for a beginner to find a compiler problem that millions of experienced programmers have not found in years is so small I wouldn’t know how to express it in a number.
Finally, the use of threads is such a complex subject that even most experienced users have difficulty using properly. I myself avoid to the fullest and only take risks when there really is much need, and look for abstractions (layers of higher level) that make me not have to deal with threads directly. If you do not have a large programming domain, broad knowledge about the functioning of the computer, operating system (not as a user but rather its internal functioning, even if not every detail), platform (JVM in your case) and all the implications on parallel processing and eventually concurrent processing, it’s best to stay away from them for now. I understand you want to learn but jumping a step will make you fall into a hole and not climb the ladder faster.
But I need to try to give an objective answer to your "problem".
No problem
You didn’t say what problem you are seeing in the result. I don’t see any problem. The result is perfect and I don’t see any problems in your code (at least for what you want, there are even some things that could be done differently, but this is another matter).
Synchronicity
You speak in synchronism. Synchronism is a concept often used in threads but that you didn’t use and even if you had used it wouldn’t bring the result you expect (or that I think you expect). Do you think you are running out of order? Do you think you should merge the "hi" and the "bye" each waiting 1.5 and the other 2 seconds, straight?
This will only happen by the purest coincidence. The threads are two completely independent executions. Nothing guarantees the order of their executions. The time in each thread is being respected. If you repeat the execution of this code several times, some of them will bring slightly different results. But both will do everything that has to be correctly. It’s just not in the order you want.
If you need control in the order of execution and the results, which should be what you call synchronization, you cannot send two distinct agents (the threads) do tasks that are interdependent (which seems to be, if I understood right) and achieve performance and predictability.
Practical examples
Here’s a piece of information that can help you understand, just a little bit, the workings of threads. Another source interesting that speaks of C#, but the general concept serves for any language.
If we take the example of motoboy, You’re sending two couriers to make 15 deliveries but each with a different distance between recipients. Just don’t consider that each one has his own time to start the bike, each one will pick up the traffic in a different way. And if synchronizing the two will probably slow down the delivery, after all synchronizing means one is waiting for the other to do his part. There are good cases to synchronize but many times if you need to synchronize you may be slowing down an agent to perform the entire task. Not to mention the possibility of creating a race condition where one waits or the other and both go nowhere.
Exactly what exit did you expect? A thread sleeps 1.5 seconds, and the other sleeps 2 seconds, so I expected something more or less the same as what happened: alternating and from time to time some identical sequences. In multi-threaded code, unless you explicitly Sincronize the actions (Synchronized, mutex, volatile, Atomic, etc.), virtually anything can happen...
– marcus
Take a look at [tour]. You can accept an answer if it solved your problem. You can vote on every post on the site as well. Did any help you more? You need something to be improved?
– Maniero