Will class locks and object locks conflict? Will object locks and private locks conflict? Illustration through examples.
1. Relevant Agreements
In order to clarify the following description, we first make the following conventions on the relevant definitions of locks involved in this article:
1. Class lock: Add static and synchronized locks to the methods in the code, or synchronized (xxx.class) code segments, such as increament() below;
2. Object lock: Add a synchronized lock to the method in the code, or a synchronized(this) code segment, such as synOnMethod() and synInMethod() below;
3. Private lock: Declare a private property such as private Object lock inside the class, and synchronize(lock) the code segment that needs to be locked, such as synMethodWithObj() below.
2. Test code
1. Write a startup class ObjectLock
Copy the code code as follows:
public class ObjectLock {
public static void main(String[] args) {
System.out.println("start time = " + System.currentTimeMillis()+"ms");
LockTestClass test = new LockTestClass();
for (int i = 0; i < 3; i++) {
Thread thread = new ObjThread(test, i);
thread.start();
}
}
}
2. Write a thread class ObjThread to start the synchronization method (note that its run method may be adjusted for different tests)
Copy the code code as follows:
public class ObjThread extends Thread {
LockTestClass lock;
int i = 0;
public ObjThread(LockTestClass lock, int i) {
this.lock = lock;
this.i = i;
}
public void run() {
//Lockless method
//lock.noSynMethod(this.getId(),this);
//Object lock method 1, using synchronized synInMethod
lock.synInMethod();
//Object lock method 2, using synchronized(this) method
//lock.synOnMethod();
//Private lock method, using synchronized(object) method
//lock.synMethodWithObj();
//Class lock method, using static synchronized increment method
LockTestClass.increment();
}
}
3. Write another lock test class LockTestClass, including various locking methods
Copy the code code as follows:
public class LockTestClass {
//Used for class lock counting
private static int i = 0;
//Private lock
private Object object = new Object();
/**
* <p>
* Lock-free method
*
* @param threadID
* @param thread
*/
public void noSynMethod(long threadID, ObjThread thread) {
System.out.println("nosyn: class obj is " + thread + ", threadId is"
+ threadID);
}
/**
* Object lock method 1
*/
public synchronized void synOnMethod() {
System.out.println("synOnMethod begins" + ", time = "
+ System.currentTimeMillis() + "ms");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synOnMethod ends");
}
/**
* Object lock method 2, use synchronized (this) to lock
*/
public void synInMethod() {
synchronized (this) {
System.out.println("synInMethod begins" + ", time = "
+ System.currentTimeMillis() + "ms");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synInMethod ends");
}
}
/**
* Object lock method 3
*/
public void synMethodWithObj() {
synchronized (object) {
System.out.println("synMethodWithObj begins" + ", time = "
+ System.currentTimeMillis() + "ms");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synMethodWithObj ends");
}
}
/**
* Class lock
*/
public static synchronized void increament() {
System.out.println("class synchronized. i = " + i + ", time = "
+ System.currentTimeMillis() + "ms");
i++;
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("class synchronized ends.");
}
}
3. Test results
1. To test class locks and object locks, modify the run method of ObjectThread as follows:
Copy the code code as follows:
public void run() {
//Lockless method
//lock.noSynMethod(this.getId(),this);
//Object lock method 1, using synchronized synInMethod
lock.synInMethod();
//Object lock method 2, using synchronized(this) method
//lock.synOnMethod();
//Private lock method, using synchronized(object) method
//lock.synMethodWithObj();
//Class lock method, using static synchronized increment method
LockTestClass.increament();
}
Terminal output:
Copy the code code as follows:
start time = 1413101360231ms
synInMethod begins, time = 1413101360233ms
synInMethod ends
class synchronized. i = 0, time = 1413101362233ms
synInMethod begins, time = 1413101362233ms
class synchronized ends.
synInMethod ends
class synchronized. i = 1, time = 1413101364233ms
synInMethod begins, time = 1413101364233ms
class synchronized ends.
synInMethod ends
class synchronized. i = 2, time = 1413101366234ms
class synchronized ends.
You can see that the object lock method (synInMothod) is 2 seconds faster than the class lock method (increament) when it is first started. This is because when synInMehtod is executed, it sleeps for 2 seconds and then executes increament, and these two methods share the same thread. So it will be 2 seconds slower. If increament is placed in front of synInMethod in run, then increament will be 2 seconds faster when it is started for the first time.
When the class lock method is started, the object lock method of another thread is also started almost at the same time, indicating that the two are not using the same lock and there will be no competition.
Conclusion: Class locks and object locks will not compete, and their locking methods will not affect each other.
2. Private locks and object locks, the run method of ObjectThread is modified as follows:
Copy the code code as follows:
public void run() {
//Lockless method
//lock.noSynMethod(this.getId(),this);
//Object lock method 1, using synchronized synInMethod
lock.synInMethod();
//Object lock method 2, using synchronized(this) method
//lock.synOnMethod();
//Private lock method, using synchronized(object) method
lock.synMethodWithObj();
//Class lock method, using static synchronized increment method
//LockTestClass.increament();
}
Terminal output:
Copy the code code as follows:
start time = 1413121912406ms
synInMethod begins, time = 1413121912407ms.
synInMethod ends.
synMethodWithObj begins, time = 1413121914407ms
synInMethod begins, time = 1413121914407ms.
synInMethod ends.
synMethodWithObj ends
synInMethod begins, time = 1413121916407ms.
synMethodWithObj begins, time = 1413121916407ms
synInMethod ends.
synMethodWithObj ends
synMethodWithObj begins, time = 1413121918407ms
synMethodWithObj ends
Very similar to class locks and object locks.
Conclusion: Private locks and object locks will not compete, and their locking methods will not affect each other.
3.Synchronized is directly added to the method and synchronized(this), and the run method of ObjectThread is modified as follows:
Copy the code code as follows:
public void run() {
//Lockless method
//lock.noSynMethod(this.getId(),this);
//Object lock method 1, using synchronized synInMethod
lock.synInMethod();
//Object lock method 2, using synchronized(this) method
lock.synOnMethod();
//Private lock method, using synchronized(object) method
//lock.synMethodWithObj();
//Class lock method, using static synchronized increment method
//LockTestClass.increament();
}
Terminal output:
Copy the code code as follows:
start time = 1413102913278ms
synInMethod begins, time = 1413102913279ms
synInMethod ends
synInMethod begins, time = 1413102915279ms
synInMethod ends
synOnMethod begins, time = 1413102917279ms
synOnMethod ends
synInMethod begins, time = 1413102919279ms
synInMethod ends
synOnMethod begins, time = 1413102921279ms
synOnMethod ends
synOnMethod begins, time = 1413102923279ms
synOnMethod ends
As you can see, the two output strictly serially (of course, whether synInMethod or synOnMethod is run first when executing again is not determined, depending on who obtains the lock).
Conclusion: synchronized directly added to the method and synchronized(this) both lock the current object. The two locking methods are in a competitive relationship, and only one method can be executed at the same time.