Hi I’m trying to understand my code, I have user synchronized key word in a method, to make that only one thread use it.
The main class:
public class Principal { public static void main(String[] args) { Messenger messenger = new Messenger(); Hilo t1 = new Hilo(messenger); Hilo t2 = new Hilo(messenger); t1.start(); t2.start(); } }
The messenger class:
public class Messenger { private String msg = "hello"; synchronized public void sendMessage() { System.out.println(msg + " from " + Thread.currentThread().getName()); } }
And the thred class:
public class Hilo extends Thread { private Messenger messenger; public Hilo(Messenger messenger) { this.messenger = messenger; } @Override public void run() { while (true) { messenger.sendMessage(); } } }
I had this output:
hello from Thread-1 hello from Thread-1 hello from Thread-1 hello from Thread-1 hello from Thread-1 hello from Thread-0 hello from Thread-0 hello from Thread-1 hello from Thread-1 hello from Thread-1 hello from Thread-1 hello from Thread-0 hello from Thread-0 hello from Thread-0 hello from Thread-0 hello from Thread-0 hello from Thread-0 hello from Thread-0 ...
But I was expected this:
hello from Thread-1 hello from Thread-0 hello from Thread-1 hello from Thread-0 hello from Thread-1 hello from Thread-0 hello from Thread-1 hello from Thread-0 hello from Thread-1 hello from Thread-0 hello from Thread-1 hello from Thread-0 hello from Thread-1 hello from Thread-0 ...
I’ve been thinking but I can’t understand the failure.
Please add your opinion .
Thanks in advance.
Answer
Always use timestamps to verify order of happening
Actually, System.out.println
makes poor mechanism for testing concurrency. The calls do not actually get output in the order they were called. In other words, never rely on the order of appearance in System.out
as representing actual order of happening.
You can see this behavior by including calls to Instant.now()
or System.nanoTime
. I suggest always adding such calls in almost any kind of testing/debugging where order matters. If you look carefully at the microseconds, you will see later items appearing on your console before earlier items.
Even better suggestion: Put your outputs into a thread-safe collection. Dump to console at end of your test.
Executor service
In modern Java, we rarely need to address the Thread
class directly.
Instead, use an executor service. The service is backed by a pool of one or more threads. The service handles creating and recreating threads as needed, depending on its promised behavior.
Write your task as a Runnable
, an object with a run
method, or a Callable
with an call
method.
Example code
Here is my revised version of your code.
Our singleton Messenger
class. One instance to be shared across two threads.
Tip: Call Thread#getId
rather than Thread#getName
to identify a thread. Virtual threads in the future Project Loom may lack names by default.
package work.basil.example.order; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Messenger { final private String msg = "hello"; final List < String > outputs = new ArrayList <>( 100 ); // Need not be thread-safe for this demo, as we only touch it from within our `synchronized` method `sendMessage`. synchronized public void sendMessage ( ) { String output = this.msg + " from thread id # " + Thread.currentThread().getId() + " at " + Instant.now(); this.outputs.add( output ); } }
Our Runnable
task class. It keeps hold of a Messenger
object to be used on each run
execution.
Tip: Rather than running endlessly as seen in your code with while ( true )
, write while ( ! Thread.interrupted() )
to run until the interrupted
flag has been thrown for that thread. The ExecutorService#shutdownNow
method will likely set that flag for us, enabling our threads to shut themselves down.
package work.basil.example.order; import java.util.Objects; public class Hilo implements Runnable { // Member fields final private String id; final private Messenger messenger; // Constructors public Hilo ( final String id , final Messenger messenger ) { this.id = id; this.messenger = Objects.requireNonNull( messenger ); } @Override public void run ( ) { while ( ! Thread.interrupted() ) { this.messenger.sendMessage(); } } }
An app class to exercise run our demo.
package work.basil.example.order; import java.time.Instant; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class App { public static void main ( String[] args ) { App app = new App(); app.demo(); } private void demo ( ) { Messenger messenger = new Messenger(); ExecutorService executorService = Executors.newFixedThreadPool( 2 ); System.out.println( "INFO - Submitting tasks. " + Instant.now() ); executorService.submit( new Hilo( "Alice" , messenger ) ); executorService.submit( new Hilo( "Bob" , messenger ) ); executorService.shutdown(); try { // Wait a while for existing tasks to terminate if ( ! executorService.awaitTermination( 15 , TimeUnit.MILLISECONDS ) ) { executorService.shutdownNow(); // Set "interrupted" flag on threads currently executing tasks. // Wait a while for tasks to respond to interrupted flag being set. if ( ! executorService.awaitTermination( 1 , TimeUnit.SECONDS ) ) System.err.println( "WARN - executorService did not terminate." ); } } catch ( InterruptedException e ) { e.printStackTrace(); } System.out.println( "INFO - Done with demo. Results array appears next. " + Instant.now() ); int nthOutput = 0; for ( String output : messenger.outputs ) { nthOutput++; System.out.println( "output " + nthOutput + " = " + output ); } } }
When run on my Mac mini Intel with six real cores and no Hyper-Threading using early-access Java 17, I see dozens of outputs at a time per thread. Notice in this sample below how the first 3 are thread ID 14, followed by # 4-71 being all thread ID 15.
As the Answer by David Schwartz explains, letting a thread run a while is usually more efficient.
INFO - Submitting tasks. 2021-03-23T02:46:58.490916Z INFO - Done with demo. Results array appears next. 2021-03-23T02:46:58.527018Z output 1 = hello from thread id # 14 at 2021-03-23T02:46:58.509450Z output 2 = hello from thread id # 14 at 2021-03-23T02:46:58.522884Z output 3 = hello from thread id # 14 at 2021-03-23T02:46:58.522923Z output 4 = hello from thread id # 15 at 2021-03-23T02:46:58.522956Z output 5 = hello from thread id # 15 at 2021-03-23T02:46:58.523011Z output 6 = hello from thread id # 15 at 2021-03-23T02:46:58.523041Z output 7 = hello from thread id # 15 at 2021-03-23T02:46:58.523077Z output 8 = hello from thread id # 15 at 2021-03-23T02:46:58.523106Z output 9 = hello from thread id # 15 at 2021-03-23T02:46:58.523134Z output 10 = hello from thread id # 15 at 2021-03-23T02:46:58.523165Z output 11 = hello from thread id # 15 at 2021-03-23T02:46:58.523197Z output 12 = hello from thread id # 15 at 2021-03-23T02:46:58.523227Z output 13 = hello from thread id # 15 at 2021-03-23T02:46:58.523254Z output 14 = hello from thread id # 15 at 2021-03-23T02:46:58.523282Z output 15 = hello from thread id # 15 at 2021-03-23T02:46:58.523312Z output 16 = hello from thread id # 15 at 2021-03-23T02:46:58.523343Z output 17 = hello from thread id # 15 at 2021-03-23T02:46:58.523381Z output 18 = hello from thread id # 15 at 2021-03-23T02:46:58.523410Z output 19 = hello from thread id # 15 at 2021-03-23T02:46:58.523436Z output 20 = hello from thread id # 15 at 2021-03-23T02:46:58.523466Z output 21 = hello from thread id # 15 at 2021-03-23T02:46:58.523495Z output 22 = hello from thread id # 15 at 2021-03-23T02:46:58.523522Z output 23 = hello from thread id # 15 at 2021-03-23T02:46:58.523550Z output 24 = hello from thread id # 15 at 2021-03-23T02:46:58.523583Z output 25 = hello from thread id # 15 at 2021-03-23T02:46:58.523612Z output 26 = hello from thread id # 15 at 2021-03-23T02:46:58.523640Z output 27 = hello from thread id # 15 at 2021-03-23T02:46:58.523668Z output 28 = hello from thread id # 15 at 2021-03-23T02:46:58.523696Z output 29 = hello from thread id # 15 at 2021-03-23T02:46:58.523760Z output 30 = hello from thread id # 15 at 2021-03-23T02:46:58.523798Z output 31 = hello from thread id # 15 at 2021-03-23T02:46:58.523828Z output 32 = hello from thread id # 15 at 2021-03-23T02:46:58.523858Z output 33 = hello from thread id # 15 at 2021-03-23T02:46:58.523883Z output 34 = hello from thread id # 15 at 2021-03-23T02:46:58.523915Z output 35 = hello from thread id # 15 at 2021-03-23T02:46:58.523943Z output 36 = hello from thread id # 15 at 2021-03-23T02:46:58.523971Z output 37 = hello from thread id # 15 at 2021-03-23T02:46:58.523996Z output 38 = hello from thread id # 15 at 2021-03-23T02:46:58.524020Z output 39 = hello from thread id # 15 at 2021-03-23T02:46:58.524049Z output 40 = hello from thread id # 15 at 2021-03-23T02:46:58.524077Z output 41 = hello from thread id # 15 at 2021-03-23T02:46:58.524102Z output 42 = hello from thread id # 15 at 2021-03-23T02:46:58.524128Z output 43 = hello from thread id # 15 at 2021-03-23T02:46:58.524156Z output 44 = hello from thread id # 15 at 2021-03-23T02:46:58.524181Z output 45 = hello from thread id # 15 at 2021-03-23T02:46:58.524212Z output 46 = hello from thread id # 15 at 2021-03-23T02:46:58.524239Z output 47 = hello from thread id # 15 at 2021-03-23T02:46:58.524262Z output 48 = hello from thread id # 15 at 2021-03-23T02:46:58.524284Z output 49 = hello from thread id # 15 at 2021-03-23T02:46:58.524308Z output 50 = hello from thread id # 15 at 2021-03-23T02:46:58.524336Z output 51 = hello from thread id # 15 at 2021-03-23T02:46:58.524359Z output 52 = hello from thread id # 15 at 2021-03-23T02:46:58.524381Z output 53 = hello from thread id # 15 at 2021-03-23T02:46:58.524405Z output 54 = hello from thread id # 15 at 2021-03-23T02:46:58.524428Z output 55 = hello from thread id # 15 at 2021-03-23T02:46:58.524454Z output 56 = hello from thread id # 15 at 2021-03-23T02:46:58.524477Z output 57 = hello from thread id # 15 at 2021-03-23T02:46:58.524499Z output 58 = hello from thread id # 15 at 2021-03-23T02:46:58.524521Z output 59 = hello from thread id # 15 at 2021-03-23T02:46:58.524544Z output 60 = hello from thread id # 15 at 2021-03-23T02:46:58.524570Z output 61 = hello from thread id # 15 at 2021-03-23T02:46:58.524591Z output 62 = hello from thread id # 15 at 2021-03-23T02:46:58.524613Z output 63 = hello from thread id # 15 at 2021-03-23T02:46:58.524634Z output 64 = hello from thread id # 15 at 2021-03-23T02:46:58.524659Z output 65 = hello from thread id # 15 at 2021-03-23T02:46:58.524685Z output 66 = hello from thread id # 15 at 2021-03-23T02:46:58.524710Z output 67 = hello from thread id # 15 at 2021-03-23T02:46:58.524731Z output 68 = hello from thread id # 15 at 2021-03-23T02:46:58.524752Z output 69 = hello from thread id # 15 at 2021-03-23T02:46:58.524780Z output 70 = hello from thread id # 15 at 2021-03-23T02:46:58.524801Z output 71 = hello from thread id # 15 at 2021-03-23T02:46:58.524826Z output 72 = hello from thread id # 14 at 2021-03-23T02:46:58.524852Z output 73 = hello from thread id # 14 at 2021-03-23T02:46:58.524902Z output 74 = hello from thread id # 14 at 2021-03-23T02:46:58.524929Z output 75 = hello from thread id # 14 at 2021-03-23T02:46:58.524954Z output 76 = hello from thread id # 14 at 2021-03-23T02:46:58.524975Z output 77 = hello from thread id # 14 at 2021-03-23T02:46:58.524998Z output 78 = hello from thread id # 14 at 2021-03-23T02:46:58.525021Z output 79 = hello from thread id # 14 at 2021-03-23T02:46:58.525042Z output 80 = hello from thread id # 14 at 2021-03-23T02:46:58.525075Z output 81 = hello from thread id # 14 at 2021-03-23T02:46:58.525095Z output 82 = hello from thread id # 14 at 2021-03-23T02:46:58.525115Z output 83 = hello from thread id # 14 at 2021-03-23T02:46:58.525138Z output 84 = hello from thread id # 14 at 2021-03-23T02:46:58.525159Z output 85 = hello from thread id # 14 at 2021-03-23T02:46:58.525194Z output 86 = hello from thread id # 14 at 2021-03-23T02:46:58.525215Z output 87 = hello from thread id # 14 at 2021-03-23T02:46:58.525241Z output 88 = hello from thread id # 14 at 2021-03-23T02:46:58.525277Z output 89 = hello from thread id # 14 at 2021-03-23T02:46:58.525298Z output 90 = hello from thread id # 14 at 2021-03-23T02:46:58.525319Z output 91 = hello from thread id # 14 at 2021-03-23T02:46:58.525339Z output 92 = hello from thread id # 14 at 2021-03-23T02:46:58.525359Z output 93 = hello from thread id # 14 at 2021-03-23T02:46:58.525381Z output 94 = hello from thread id # 14 at 2021-03-23T02:46:58.525401Z output 95 = hello from thread id # 14 at 2021-03-23T02:46:58.525422Z output 96 = hello from thread id # 14 at 2021-03-23T02:46:58.525452Z output 97 = hello from thread id # 14 at 2021-03-23T02:46:58.525474Z output 98 = hello from thread id # 14 at 2021-03-23T02:46:58.525496Z output 99 = hello from thread id # 14 at 2021-03-23T02:46:58.525515Z output 100 = hello from thread id # 14 at 2021-03-23T02:46:58.525533Z output 101 = hello from thread id # 14 at 2021-03-23T02:46:58.525555Z output 102 = hello from thread id # 14 at 2021-03-23T02:46:58.525581Z output 103 = hello from thread id # 14 at 2021-03-23T02:46:58.525603Z output 104 = hello from thread id # 14 at 2021-03-23T02:46:58.525625Z output 105 = hello from thread id # 14 at 2021-03-23T02:46:58.525645Z output 106 = hello from thread id # 14 at 2021-03-23T02:46:58.525664Z output 107 = hello from thread id # 14 at 2021-03-23T02:46:58.525686Z output 108 = hello from thread id # 14 at 2021-03-23T02:46:58.525705Z output 109 = hello from thread id # 14 at 2021-03-23T02:46:58.525723Z output 110 = hello from thread id # 14 at 2021-03-23T02:46:58.525741Z output 111 = hello from thread id # 14 at 2021-03-23T02:46:58.525758Z output 112 = hello from thread id # 14 at 2021-03-23T02:46:58.525783Z output 113 = hello from thread id # 14 at 2021-03-23T02:46:58.525801Z output 114 = hello from thread id # 14 at 2021-03-23T02:46:58.525818Z output 115 = hello from thread id # 14 at 2021-03-23T02:46:58.525837Z output 116 = hello from thread id # 14 at 2021-03-23T02:46:58.525855Z output 117 = hello from thread id # 14 at 2021-03-23T02:46:58.525875Z output 118 = hello from thread id # 14 at 2021-03-23T02:46:58.525897Z output 119 = hello from thread id # 14 at 2021-03-23T02:46:58.525913Z output 120 = hello from thread id # 15 at 2021-03-23T02:46:58.525931Z output 121 = hello from thread id # 15 at 2021-03-23T02:46:58.525965Z output 122 = hello from thread id # 15 at 2021-03-23T02:46:58.526002Z output 123 = hello from thread id # 15 at 2021-03-23T02:46:58.526023Z output 124 = hello from thread id # 15 at 2021-03-23T02:46:58.526050Z output 125 = hello from thread id # 15 at 2021-03-23T02:46:58.526075Z output 126 = hello from thread id # 15 at 2021-03-23T02:46:58.526095Z output 127 = hello from thread id # 15 at 2021-03-23T02:46:58.526135Z output 128 = hello from thread id # 15 at 2021-03-23T02:46:58.526169Z output 129 = hello from thread id # 15 at 2021-03-23T02:46:58.526233Z output 130 = hello from thread id # 15 at 2021-03-23T02:46:58.526260Z output 131 = hello from thread id # 15 at 2021-03-23T02:46:58.526279Z output 132 = hello from thread id # 15 at 2021-03-23T02:46:58.526297Z output 133 = hello from thread id # 15 at 2021-03-23T02:46:58.526315Z output 134 = hello from thread id # 15 at 2021-03-23T02:46:58.526335Z output 135 = hello from thread id # 15 at 2021-03-23T02:46:58.526352Z output 136 = hello from thread id # 15 at 2021-03-23T02:46:58.526370Z output 137 = hello from thread id # 15 at 2021-03-23T02:46:58.526389Z output 138 = hello from thread id # 15 at 2021-03-23T02:46:58.526405Z output 139 = hello from thread id # 15 at 2021-03-23T02:46:58.526424Z output 140 = hello from thread id # 15 at 2021-03-23T02:46:58.526441Z output 141 = hello from thread id # 14 at 2021-03-23T02:46:58.526465Z output 142 = hello from thread id # 14 at 2021-03-23T02:46:58.526500Z output 143 = hello from thread id # 14 at 2021-03-23T02:46:58.526524Z output 144 = hello from thread id # 14 at 2021-03-23T02:46:58.526552Z output 145 = hello from thread id # 14 at 2021-03-23T02:46:58.526570Z output 146 = hello from thread id # 14 at 2021-03-23T02:46:58.526588Z output 147 = hello from thread id # 14 at 2021-03-23T02:46:58.526605Z output 148 = hello from thread id # 14 at 2021-03-23T02:46:58.526621Z output 149 = hello from thread id # 14 at 2021-03-23T02:46:58.526642Z output 150 = hello from thread id # 14 at 2021-03-23T02:46:58.526658Z output 151 = hello from thread id # 14 at 2021-03-23T02:46:58.526674Z output 152 = hello from thread id # 14 at 2021-03-23T02:46:58.526696Z output 153 = hello from thread id # 15 at 2021-03-23T02:46:58.526715Z