Home  >  Article  >  Java  >  Use of synchronized keyword

Use of synchronized keyword

(*-*)浩
(*-*)浩forward
2019-09-06 16:02:142463browse

The synchronized keyword is a synchronization lock commonly used in Java concurrent programming. It is used to lock methods or code blocks. When locking code blocks, it can be synchronized(this){}, synchronized(Object){}, synchronized(class) {}.

Use of synchronized keyword

#The lock will be automatically released when the locked content is executed or an exception is thrown during execution.

If you want to manually release the lock, you need to call the wait() method of the locked object to release the lock and put it in a waiting state, switch to other threads to run, and the notify() method only wakes up the object that has been called. wait() method of other threads, but the lock will not be released, and the selection order is not controlled by the code and is implemented by the virtual machine.

Therefore, the wait(), notify(), and notifyAll() methods of the object can only be used with the synchronized keyword to complete scheduling between threads.

The locked method is equivalent to synchronized(this){all the code of the method as a code block}, as follows:

public synchronized void test() {
...
}

Equivalent to

public void test() {
synchronized (this) {
...
}
}

The above example is locked is an object of this class. If a static method is locked, we know that the static method belongs to the class and not to the object. Therefore, the static method modified by synchronized locks all objects of this class, that is, even two Instance objects, as long as they belong to this class, will be locked.

public synchronized static void test() {
	...
}

Equivalent to

public static void test() {
synchronized (所在类.class) {
...
}	
}

Whether it is a lock method or a code block, no matter what the reference object is when locking the code block, it is clear as long as you remember one principle, that is, when the reference object Synchronization locks only work when they are the same, otherwise the locks will not be mutually exclusive and can be executed concurrently.

synchronized(this) indicates that the lock takes effect when the object instances of the current class are the same, synchronized(Object) indicates that the lock takes effect when the Object objects are the same, and synchronized(class) indicates that the lock takes effect when they are all of the same class. kick in.

Give a simple example:

public class TestController {
 
    public class Task implements Runnable{
		private String str;
		
		Task(String str){
			this.str=str;
		}
		
		@Override
		public void run() {
			synchronized (str) {
				try {
					Thread.sleep(3000l);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(str);
			}
		}
		
	}
	
	public static void main(String[] args) throws InterruptedException {
		TestController testController = new TestController();
		Thread thread1 = new Thread(testController.new Task("1"));
		Thread thread2 = new Thread(testController.new Task("1"));
		thread1.start();
		thread2.start();
	}
}

In the above code, the reference object str is "1". In java, if the String string passes this.str="1", Assignment is equivalent to str=String.valueOf("1"). If the string "1" has been initialized before, the previous one will be taken directly, so it is the same object. According to the principle introduced above, the lock will take effect, so the result is that 1 will be output after 3 seconds, and 1 will be output after another 3 seconds.

If thread2 is changed to

Thread thread2 = new Thread(testController.new Task("2"));

then one of the reference objects is "1" and the other is "2", which are not the same object, so the lock will not be mutually exclusive, and it will not works, so the result is that 1 and 2 are output almost simultaneously after 3 seconds.

All of the above are multiple threads calling the same method at the same time. What if different methods are called?

public class Test{
	
	public synchronized void m1(){
		System.out.println("m1 running...");
		try {
			Thread.sleep(3000l);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("m1 end");
	}
	
	public synchronized void m2(){
		System.out.println("m2 running...");
		System.out.println("m2 end");
	}
	
	public static void main(String[] args) {
		Test test = new Test();
		new Thread(new Runnable() {
			@Override
			public void run() {
				test.m1();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				test.m2();
			}
		}).start();
	}
	
}

The output result of the above code is:

m1 running...
//过3秒
m1 end
m2 running...
m2 end

As mentioned above, the synchronized modification is equivalent to synchronized(this){all the code of the method as a code block}, and this represents is an object, that is to say, the first Thread obtains the lock of the test object. Because the objects are all the same test, the second Thread cannot obtain the lock and is blocked.

Change the above example into the following:

private String str = "1";
	
public void m1(){
	synchronized(str){
		System.out.println("m1 running...");
		try {
			Thread.sleep(3000l);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("m1 end");
	}
}
 
public void m2(){
	synchronized(str){
		System.out.println("m2 running...");
		System.out.println("m2 end");
	}
}

When the first Thread calls m1(), it obtains the lock of the object str, and the second Thread also needs it when it calls m2(). Obtain the lock of the object str, and because they are the same Test object, the two strs are also the same object, so the second Thread will be blocked because it cannot obtain the lock, and the output result is the same as the previous example.

If the above example is transformed into the following:

public class M1 {
	
	public void m(String str){
		synchronized (str) {
			System.out.println("m1 runing");
			try {
				Thread.sleep(3000l);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("m1 end");
		}
	}
 
}
public class M2 {
	
	public void m(String str){
		synchronized (str) {
			System.out.println("m2 runing");
			System.out.println("m2 end");
		}
	}
 
}
public class Test {
 
	public static void main(String[] args) {
		String str = "1";
		new Thread(new Runnable() {
			@Override
			public void run() {
				new M1().m(str);
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				new M2().m(str);
			}
		}).start();
	}
	
}

The method called this time is in two classes, but the result is the same as the previous two examples, because the locked They are all str objects passed in. There is only one lock for the same object. If the first Thread takes it, the second Thread can only wait.

Summary:

A. Regardless of whether the synchronized keyword is added to a method or an object, if the object it acts on is non-static, the lock it acquires is the object ; If the object synchronized acts on is a static method or a class, the lock it acquires is for the class, and all objects of the class have the same lock.

B. Each object has only one lock associated with it. Whoever gets this lock can run the code it controls.

C. Achieving synchronization requires a lot of system overhead and may even cause deadlock, so try to avoid unnecessary synchronization control

The above is the detailed content of Use of synchronized keyword. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete