I will give the best answer to a beginner and not exactly to solve the problem (which does not even exist).
Introduction
First, Your computer does not have a problem . Even if it were, it would not affect how the program works in this way. The program would not work at all.
Second, the chance for a beginner to find a compiler problem that the millions of experienced programmers did not find in years is so small that I would not know how to express it in a number.
Finally, using threads is such a complex subject that even most experienced users find it difficult to use correctly. I myself make the most of it and only take risks when there is really a lot of need, and I look for abstractions (higher level layers) that make me not have to deal with threads directly. If you do not have a large programming domain, extensive knowledge about the operation of the computer, operating system (not as user but rather its internal operation, if not all details), platform (JVM in your case) and all the implications on parallel and possibly concurrent processing, it is best to stay away from them for now. I understand you want to learn but skipping a step will make you fall into a hole and not climb up the ladder any faster.
But I need to try to give an objective answer to your "problem."
No problem
You did not say what problem you are seeing in the result. I do not see any problem. The result is perfect and I do not see any problems in your code (at least for what you want, there are some things that could be done otherwise, but that's another matter). >
Synchronism
You talk in sync. Synchronization is a concept used in threads but you did not use it and even if you used it would not bring the result that you expect (or that I think you expect). Do you think you are running out of order? Do you think you should insert the "hi" and "bye" each one expecting 1.5 and the other 2 seconds, right?
This will only happen by pure coincidence. The threads are two completely independent runs. Nothing guarantees the order of your executions . The time in each thread is being respected. If you repeat running this code multiple times, some of them will bring slightly different results. But both will do everything that has to be right. It's just not in the order you want.
If you need control in the order of execution and results, which should be what you call synchronization, you can not have two distinct agents (threads ) do tasks that are interdependent what seems to be, if I understood correctly) and achieve performance and predictability.
Practical examples
Here is an information that can help you understand, just a little, the operation of threads . Another interesting source that talks about C #, but the general concept is good for any language.
If we take the example of motoboy , you are sending two deliverers to make 15 deliveries but each with a different distance between the recipients. Just do not consider that each one has its own time to start the bike, each one will get the traffic in a different way. And if synchronizing the two will probably make delivery slower, after all synchronizing means waiting for the other to do the part of it. There are good cases to sync but often if you need to sync you may be slowing down than having an agent perform the entire task. Not to mention the possibility of creating a race condition where one is waiting or another and both they get nowhere.