0. About thread synchronization
(1) Why do I need to sync multithreading?
thread synchronization is to allow multiple running threads to work together in a good way to allow multithreading to properly occupy released resources as required. We use the synchronized code block and synchronization method in Java to achieve this goal. For example, this solves the problem that multithreading has no fixed order execution:
public class Twothreadtest {public
static void Main (string[] args) {
Thread th1= new MyThread1 ();
Thread th2= new MyThread2 ();
Th1.start ();
Th2.start ();
}
Class MyThread2 extends thread{
@Override public
void Run () {for
(int i=0;i<10;i++)
System. OUT.PRINTLN ("Thread 1 counter:" +i);
}
Class MyThread1 extends thread{
@Override public
void Run () {for
(int i=0;i<10;i++)
System. OUT.PRINTLN ("Thread 2 counter:" +i);
}
The result of multithreaded execution in this state is random insertion into execution, which is entirely dependent on the JVM's scheduling of threads, which, in many cases requiring sequential execution, is clearly undesirable.
public class ThreadTest {public
static void Main (string[] args) {
mythread thread = new Mythread ();
Thread th1= new Thread (thread);
Thread th2= new Thread (thread);
Th1.start ();
Th2.start ();
}
Class Mythread implements runnable{
@Override public
synchronized void Run () {for
(int i=0;i<10;i++)
System. Out.println (Thread. CurrentThread (). GetName () + counter: +i);
}
After using the synchronization method, we can control the thread exclusive execution object, so that in the course of execution, the thread will leave the lock state after executing the task on the body once, and the JVM can dispatch another thread to run the task of executing the body at once.
(2) Threads create a running paradigm:
in the past we had our own thread-creating and running programming paradigm, which generally defined an executive class rewrite the Run () method, but this way put the execution body and the task of execution together, from the point of view of software engineering is not conducive to decoupling. The execution of a thread means that a thread performs a task on an object by executing an object. From this perspective, separating the task's mandate from the Executive class can make the various roles of multithreaded programming clear, and thus get a good decoupling, and here is the programming paradigm for thread creation and execution:
public class Formalthreadclass {public
static void Main (string[] args) {
thread thread = new Thread (New Myrunnab Le ());
Thread.Start ();
}
Class Myrunnable implements runnable{
mytask mytask = new MyTask ();
@Override public
Void Run () {
mytask.dotask ();
}
}
Class mytask{public
void Dotask () {
System. Out.println (' This was real tasking ');
}
1. Synchronized principle
in Java, each object has and has only one synchronization lock. This also means that the synchronization lock is dependent on the object and exists.
When we call the Synchronized method of an object, we get a synchronized lock on the object. For example, synchronized (obj) acquires a synchronized lock on the "obj" object.
The access of different threads to the synchronization lock is mutually exclusive. In other words, a point in time, the object's synchronization lock can only be obtained by a thread! By synchronizing the locks, we can implement mutually exclusive access to the object/method in multiple threads. For example, there are now two threads A and thread B that will access the synchronization lock for object obj. Suppose, at some point, thread a gets to "obj's Sync lock" and performs some action; at this point, thread B also attempts to get "obj's Sync lock"--thread B gets failed, and it must wait until thread a releases "Sync lock for this object" before thread B gets the "Sync Lock for obj" So that they can run.
2. Synchronized Basic rules
We summarize the basic rules of synchronized into the following 3 articles and illustrate them through an instance.
First: When a thread accesses the synchronized method or synchronized code block of an object, the synchronized method or synchronized code block for that object by another thread Access will be blocked.
Second article: When one thread accesses the synchronized method or synchronized code block of an object, other threads can still access the asynchronous code block of the object.
Third: When one thread accesses the synchronized method or synchronized code block of an object, other threads "synchronized method" or "Synchronized code block" for "this object" Access will be blocked.
(1) First:
when one thread accesses the synchronized method or synchronized code block of an object, the other thread has the synchronized method for that object or "Synchronized code block" Access will be blocked. The following is the demo program for "Synchronized code block".
Class Myrunable implements Runnable {
@Override public
void Run () {
synchronized (this) {
try {
int i = 0; I < 5; i++) {
thread.sleep (100);//Hibernate 100ms
System.out.println (Thread.CurrentThread (). GetName () + "loop" + i);
}
' catch (Interruptedexception IE) {}}} ' public
class Demo1_1 {public
static void Main (string[] args) {
Runnable demo = new Myrunable (); New "Runnable object"
thread = T1 = new Thread (demo, "T1");//new "thread T1", T1 is based on demo this runnable object
thread t2 = new Thread ( Demo, "T2"); New "Thread T2", T2 is based on demo this runnable object
t1.start (); Start "Thread T1"
t2.start (); Start the thread T2
}
}
Run Result:
T1 Loop 0
T1 loop 1
t1 loop 2
t1 loop 3
t1 loop 4
T2 loop 0
T2 loop 1
T2 loop 2
T2 Loop 3
T2 Loop 4
Results: The "synchronized" code block exists in the run () method, and T1 and T2 are threads created based on the "demo this Runnable object". This means that we can consider this as the "demo this Runnable object", and therefore thread T1 and T2 share "Sync Locks for Demo objects". Synchronized So, when a thread is running, another thread must wait for the "run thread" to release the "Demo's Sync lock" before it can run.
If you confirm, you know the problem. Let's modify the code above and then run it to see what happens and see if you're confused. The revised source code is as follows:
Class Mythread extends Thread {public
mythread (String name) {
super (name);
}
@Override public
Void Run () {
synchronized (.) {
try {for
(int i = 0; i < 5; i++) {
Thread.Sleep (100); Hibernate 100ms
System.out.println (Thread.CurrentThread (). GetName () + "loop" + i);
}
catch (Interruptedexception IE) {
}} public
class Demo1_2 {public
static void main ( String[] args {thread
t1 = new Mythread ("T1");//Create New threads T1 = ("t2"
) = new Mythread;//new "thread T2"
T2 . Start (); Start "Thread T1"
t2.start (); Start the thread T2
}
}
Code Description: Comparing Demo1_2 and demo1_1, we find that the Mythread class in Demo1_2 is directly inherited from thread, and T1 and T2 are all mythread child threads.
Fortunately, synchronized (this) was also invoked in the "Demo1_2 run" method, just as the Demo1_1 run () method also called synchronized (this)!
So, is Demo1_2 's execution process the same as demo1_1? Run Result:
T1 Loop 0
T2 loop 0
T1 loop 1
T2 loop 1
t1 loop 2
T2 loop 2
t1 loop 3
T2 loop 3
T1 loop 4< C9/>t2 Loop 4
Results show:
If this result does not surprise you at all, then I believe you have a deeper understanding of synchronized and this. Otherwise, please continue reading the analysis here.
This in synchronized (this) refers to the current object for the current class object, that is, the class in which synchronized (this) is located. Its role is to get "sync locks on the current object."
For Demo1_2, this in synchronized (this) represents the Mythread object, while T1 and T2 are two different mythread objects, so t1 and T2 when the synchronized (this) is executed, Gets the synchronized locks of different objects. For demo1_1 pairs, this in synchronized (this) represents the Myrunable object; T1 and T2 share a Myrunable object, so one thread acquires a synchronized lock on the object, causing another thread to wait.
(2) Article II:
when a thread accesses the synchronized method or synchronized code block of an object, other threads can still access the asynchronous code block of the object.
The following is the demo program for "Synchronized code block".
Class Count {//method with synchronized synchronization block public void Synmethod () {synchronized () {try {A for (int i = 0; i < 5; i++) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + "Synmethod Loop" +
i); (Interruptedexception IE) {}}}//asynchronous method public void Nonsynmethod () {try {i = 0; I < 5;
i++) {thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName () + "Nonsynmethod loop" + i); } catch (Interruptedexception IE) {}} public class Demo2 {public static void main (string[] args) {FINA
L Count count = new Count (); New T1, T1 calls the Synmethod () method of the "Count object" thread t1 = new Thread (new Runnable () {@Override public void run ()
{Count.synmethod ();
}, "T1"); New T2, T2 invokes the Nonsynmethod () method of the "Count object" thread t2 = new Thread (new Runnable () {@Override public void Ru
N () {count.nonsynmethod (); }, "T2"); T1.start (); Start T1 t2.start ();
Start T2}}
Run Result:
T1 synmethod Loop 0
T2 nonsynmethod loop 0
T1 Synmethod Loop 1
T2 Nonsynmethod loop 1
t1 Synmethod Loop 2< C5/>t2 Nonsynmethod loop 2
t1 Synmethod Loop 3
T2 Nonsynmethod loop 3
t1 Synmethod Loop 4
T2 Nonsynmethod Loop 4
Results show:
Two new child threads T1 and T2 are created in the main thread. T1 invokes the Synmethod () method of the Count object, which contains a synchronized block, while T2 invokes the Nonsynmethod () method of the Count object, which is not a synchronous method. The T1 runtime, although calling synchronized (this) gets "sync lock for Count", does not cause T2 blocking because T2 does not use the "Count" sync lock.
(3) Article III:
when a thread accesses the "synchronized method" or "Synchronized code block" of "an object", other Threads "synchronized method" or "Synchronized code block" for "this object" Access will be blocked.
We also decorate the Nonsynmethod () method Body of the above example with synchronized (this). The revised source code is as follows:
Class Count {//method with synchronized synchronization block public void Synmethod () {synchronized () {try {A for (int i = 0; i < 5; i++) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + "Synmethod Loop" +
i); The method for catch (Interruptedexception IE) {}}}//also contains synchronized synchronization blocks is public void Nonsynmethod () {Synchron
Ized (This) {try {for (int i = 0; i < 5; i++) {thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName () + "Nonsynmethod loop" + i);
} catch (Interruptedexception IE)}} public class Demo3 {public static void main (string[] args) {
Final count count = new count (); New T1, T1 calls the Synmethod () method of the "Count object" thread t1 = new Thread (new Runnable () {@Override public void run ()
{Count.synmethod ();
}, "T1");
New T2, T2 invokes the Nonsynmethod () method of the "Count object" thread t2 = new Thread (new Runnable () {@Override public void Run () {Count.nonsynmethod ();
}, "T2"); T1.start (); Start T1 t2.start ();
Start T2}}
Run Result:
T1 Synmethod Loop 0
T1 Synmethod Loop 1
t1 Synmethod loop 2
t1 Synmethod loop 3
t1 Synmethod Loop 4
T2 Nonsynmethod Loop 0
T2 nonsynmethod Loop 1
T2 Nonsynmethod loop 2
T2 Nonsynmethod loop 3
T2 Nonsynmethod Loop 4
Results show:
Two new child threads T1 and T2 are created in the main thread. The T1 and T2 runtime call synchronized (this), which is the Count object (count), and T1 and T2 share count. Therefore, when the T1 is run, T2 is blocked, waiting for T1 to run to release the sync lock of the Count object to run T2.
3. Synchronized method and synchronized code block
the "Synchronized method" is decorated with synchronized, and "synchronized code block" is a code block decorated with synchronized.
Synchronized Method Example
Public synchronized void Foo1 () {
System.out.println ("synchronized methoed");
}
Synchronized code block public
void Foo2 () {
synchronized (this) {
System.out.println ("Synchronized methoed") ;
}
}
The
Synchronized in the code block refers to the current object. You can also replace this with another object, such as replacing this with obj, Foo2 () acquires a synchronized lock for obj when executing synchronized (obj). The
Synchronized code block allows more precise control of the conflict to restrict access to the area, and sometimes to perform more efficiently. An example is shown below:
Demo4.java Source Public
class Demo4 {public
synchronized void Synmethod () {for
(int i=0; i<1000000; i++) c4/>;
}
public void Synblock () {
synchronized (a) {for
(int i=0; i<1000000; i++)
;
}
public static void Main (string[] args) {
Demo4 demo = new Demo4 ();
long Start, diff;
Start = System.currenttimemillis (); Gets the current time (Millis)
Demo.synmethod (); Invoke the "Synchronized method"
diff = system.currenttimemillis ()-Start; Get "Time difference"
System.out.println ("Synmethod ():" + diff);
Start = System.currenttimemillis (); Gets the current time (Millis)
demo.synblock (); Call "Synchronized method block"
diff = system.currenttimemillis ()-Start; Gets the "time difference"
System.out.println ("Synblock ():" + diff);
}
(one time) execution results:
Synmethod (): One
Synblock (): 3
4. Instance lock and Global lock
instance Lock--locks on an instance object. If the class is a single case, then the lock also has the concept of global locks.
(1) The instance lock corresponds to the synchronized keyword.
(2) Global lock--the lock is for a class and the thread shares the lock regardless of the number of instances of the instance.
A global lock corresponds to a static synchronized (or a lock on the class or ClassLoader object).
There is a very vivid example of the instance lock and the global lock:
Pulbic class Something {public
synchronized void Issynca () {} public
synchronized void Issyncb () {}
static synchronized void Csynca () {} public
static synchronized void Csyncb () {}
}
Suppose that something has two instances X and Y. Analyze the case of locks acquired by the following 4 groups of expressions.
(1) X.issynca () and X.ISSYNCB ()
(2) X.issynca () and Y.issynca ()
(3) X.csynca () and Y.CSYNCB ()
(4) X.issynca () and Something.csynca ()
(1) cannot be accessed concurrently.
because Issynca () and ISSYNCB () are synchronized locks that access the same object (object x)!
Locktest1.java Source class Something {public synchronized void Issynca () {try {to (int i = 0; i < 5; I
+ +) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": Issynca"); }catch (Interruptedexception IE) {}} public synchronized void Issyncb () {try {i = 0; I < 5;
i++) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": ISSYNCB");
}}catch (Interruptedexception IE) {}} public class LockTest1 {something x = new Something ();
Something y = new something ();
Compare () X.issynca () with X.ISSYNCB () private void test1 () {//New T11, T11 invokes X.issynca () thread t11 = new Thread (
New Runnable () {@Override public void run () {X.issynca ();
}, "T11");
New T12, T12 will invoke X.ISSYNCB () thread T12 = new Thread (new Runnable () { @Override public void Run () {X.ISSYNCB ();
}, "T12"); T11.start (); Start T11 t12.start ();
Start T12} public static void Main (string[] args) {LockTest1 demo = new LockTest1 ();
Demo.test1 ();
}
}
Run Result:
T11:issynca
T11:issynca
t11:issynca
t11:issynca
t11:issynca
T12:ISSYNCB C7/>T12:ISSYNCB
T12:ISSYNCB
T12:ISSYNCB
(2) can be accessed at the same time
Because the access is not a synchronous lock of the same object, X.issynca () accesses the sync lock of X, while Y.issynca () accesses the sync lock of Y.
Locktest2.java Source class Something {public synchronized void Issynca () {try {to (int i = 0; i < 5; I
+ +) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": Issynca"); }catch (Interruptedexception IE) {}} public synchronized void Issyncb () {try {i = 0; I < 5;
i++) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": ISSYNCB"); }catch (Interruptedexception IE) {}} public static synchronized void Csynca () {try {A for (int i = 0; i < 5; i++)
{thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": Csynca"); }catch (Interruptedexception IE) {}} public static synchronized void Csyncb () {try { t i = 0; I < 5; i++) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.currenttHread (). GetName () + ": CSYNCB");
}}catch (Interruptedexception IE) {}} public class LockTest2 {something x = new Something ();
Something y = new something ();
Compare () X.issynca () with Y.issynca () private void Test2 () {//New t21, T21 invokes X.issynca () thread t21 = new Thread (
New Runnable () {@Override public void run () {X.issynca ();
}, "T21"); New t22, T22 will invoke X.ISSYNCB () thread t22 = new Thread (new Runnable () {@Override public vo
ID run () {Y.issynca ();
}, "t22"); T21.start (); Start t21 T22.start ();
Start t22} public static void Main (string[] args) {LockTest2 demo = new LockTest2 ();
Demo.test2 ();
}
}
Run Result:
T21:issynca
T22:issynca
t21:issynca
t22:issynca
t21:issynca
T22:issynca C7/>t22:issynca
T21:issynca
T22:issynca
(3) cannot be accessed concurrently
because Csynca () and CSYNCB () are static types, X.csynca () is the equivalent of Something.issynca (), Y.CSYNCB () is the equivalent of SOMETHING.ISSYNCB (), So they share a synchronous lock and cannot be asked at the same time.
Locktest3.java Source class Something {public synchronized void Issynca () {try {to (int i = 0; i < 5; I
+ +) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": Issynca"); }catch (Interruptedexception IE) {}} public synchronized void Issyncb () {try {i = 0; I < 5;
i++) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": ISSYNCB"); }catch (Interruptedexception IE) {}} public static synchronized void Csynca () {try {A for (int i = 0; i < 5; i++)
{thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": Csynca"); }catch (Interruptedexception IE) {}} public static synchronized void Csyncb () {try { t i = 0; I < 5; i++) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.currenttHread (). GetName () + ": CSYNCB");
}}catch (Interruptedexception IE) {}} public class LockTest3 {something x = new Something ();
Something y = new something ();
Compare () X.csynca () with Y.CSYNCB () private void Test3 () {//New t31, T31 invokes X.issynca () thread t31 = new Thread (
New Runnable () {@Override public void run () {X.csynca ();
}, "T31"); New T32, T32 will invoke X.ISSYNCB () thread t32 = new Thread (new Runnable () {@Override public vo
ID run () {Y.CSYNCB ();
}, "T32"); T31.start (); Start T31 T32.start ();
Start T32} public static void Main (string[] args) {LockTest3 demo = new LockTest3 ();
Demo.test3 ();
}
}
Run Result:
T31:csynca
T31:csynca
t31:csynca
t31:csynca
t31:csynca
t32:csyncb T32:CSYNCB T32 : CSYNCB
T32:CSYNCB
T32:CSYNCB
(4) can be accessed concurrently
because Issynca () is an instance method, X.issynca () uses the lock of Object X, and Csynca () is a static method, and Something.csynca () can understand the "Lock of Class" for use. Therefore, they can be accessed at the same time.
Locktest4.java Source class Something {public synchronized void Issynca () {try {to (int i = 0; i < 5; I
+ +) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": Issynca"); }catch (Interruptedexception IE) {}} public synchronized void Issyncb () {try {i = 0; I < 5;
i++) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": ISSYNCB"); }catch (Interruptedexception IE) {}} public static synchronized void Csynca () {try {A for (int i = 0; i < 5; i++)
{thread.sleep (100);//Hibernate 100ms System.out.println (Thread.CurrentThread (). GetName () + ": Csynca"); }catch (Interruptedexception IE) {}} public static synchronized void Csyncb () {try { t i = 0; I < 5; i++) {thread.sleep (100);//Hibernate 100ms System.out.println (Thread.currenttHread (). GetName () + ": CSYNCB");
}}catch (Interruptedexception IE) {}} public class LockTest4 {something x = new Something ();
Something y = new something (); Compare () X.issynca () with Something.csynca () private void test4 () {//New t41, T41 will invoke X.issynca () Thread t41 = new Th
Read (new Runnable () {@Override public void run () {X.issynca ();
}, "t41"); New T42, T42 will invoke X.ISSYNCB () thread T42 = new Thread (new Runnable () {@Override public vo
ID run () {Something.csynca ();
}, "T42"); T41.start (); Start t41 T42.start ();
Start T42} public static void Main (string[] args) {LockTest4 demo = new LockTest4 ();
Demo.test4 ();
}
}
Run Result:
T41:issynca
T42:csynca
t41:issynca
t42:csynca
t41:issynca
T42:csynca >t42:csynca
T41:issynca
T42:csynca