I am trying in the Synchronized () {}
button to synchronize the arraylist
object. In a separate thread, I capture this object in Synchronized
, write a value (first
), throw the flow into sleep for 1 sec. And throwing the following value (Second
). The main stream, after starting the flow with Synchronized
, throw in a dream for 1 sec. And I write a value (Last
).
As I understood from the study: The object transferred to the Synchronized
unit is not available to another stream, before the object is output from the block. Those. The array queue will be: first
, Second
, Last
. In my example, queue: first
, Last
, Second
. Those. The main thread addressed the array object before the object is output from the Synchronized
block.
How to properly organize object synchronization, i.e. What would there be access to it before exiting the block?
Code:
import java.util.arraylist;
Public Class Main {
STATIC PUBLIC VOID MAIN (String Args []) {
CheckSynchronized CS = new checksynchronized ();
NEW Thread (new Runnable () {
@Override
Public void Run () {
Synchronized (CS.AL) {
cs.al.add ("first");
Try {
Thread.sleep (1000);
} Catch (InterruptedException E) {
E.PrintStackTrace ();
}
cs.al.add ("Second");
}
}
}). start ();
Try {
Thread.sleep (1000);
} Catch (InterruptedException E) {
E.PrintStackTrace ();
}
cs.al.add ("Last");
CS.Al.Foreach (System.out :: PrintLN);
}
}
Class CheckSynchronized {
Public ArrayList & LT; String & GT; Al;
Checksynchronized () {
Al = New ArrayList & lt; & gt; ();
}
}
Answer 1, Authority 100%
As I understand it from learning: The object transferred to the Synchronized block is not available to another stream, before the object is output from the block.
No, you misunderstood. The object on which you synchronize is not related to the contents of this object. Just Java is so strangely arranged that you can absolutely any object to use as a synchronization monitor and without a difference, what is the object and for what else it can be used.
Synchronization sections are used to implement a “Mutual Exception” template (Mutual Exclusion, Mutex): At the same time, two synchronization sections cannot work, synchronized on one object. If you are wrapped in Al
in Synchronized (CS.al)
, as advises @vartlok, you will achieve a mutual exception. Then you will be guaranteed that either the entry first
and second
will appear before recording Last
, or they will appear after (order First, Last, SECOND
You will not see warranty). But nevertheless, concrete “before” or “after”, no one promises. Although you have been poured a second in one stream, there is no guarantee that the second stream began to be performed in this second. With very high probability, he will start, but no one guarantees. Suddenly the system is too loaded, for example.
To guarantee order, you need other mechanisms. For example, you can use countdownlach
:
checksynchronized CS = new checksynchronized ();
// Take the counter for 1
Final CountdownLatch Latch = New CountdownLatch (1);
NEW Thread (new Runnable () {
@Override
Public void Run () {
cs.al.add ("first");
Try {
Thread.sleep (1000);
} Catch (InterruptedException E) {
E.PrintStackTrace ();
}
cs.al.add ("Second");
// finished the operation - reduced the meter
Latch.countdown ();
}
}). start ();
Try {
// We wait until the meter is 0.
Latch.await ();
} Catch (InterruptedException E) {
E.PrintStackTrace ();
}
cs.al.add ("Last");
CS.Al.Foreach (System.out :: PrintLN);
So we provided a guaranteed order, and synchronization is not really needed.
In this case, there is a simpler mechanism – Thread.Join
:
checksynchronized CS = new checksynchronized ();
Thread Thread = New Thread (New Runnable () {
@Override
Public void Run () {
cs.al.add ("first");
Try {
Thread.sleep (1000);
} Catch (InterruptedException E) {
E.PrintStackTrace ();
}
cs.al.add ("Second");
}
});
thread.start ();
Try {
thread.join ();
} Catch (InterruptedException E) {
E.PrintStackTrace ();
}
cs.al.add ("Last");
CS.Al.Foreach (System.out :: PrintLN);
Since the second thread is nothing more about to do, you can simply wait for it. But if there is something else in the second thread, then to organize the events of CountdownLatch
flexible. More flexible CyclicBarrier
or Phaser
.
Answer 2, Authority 62%
Well, the behavior of the code fully corresponds to what you wrote. Synchronize
Properly checks the location of the object, and if it is not, he takes him away. Only when you add to the list "LAST"
, no one checks that the object is locked. Those. So that the code worked as you need, you need to do this:
synchronized (CS.AL) {
cs.al.add ("Last");
}
Then before adding the object location will be checked and the thread will take the object until the object will not be available.
Because You are learning multithreading, it will be useful to read the difference between Wait ()
and Sleep ()
here to not be surprised.