Java keyword synchronized

Articles Catalogue

Java keyword synchronized

I. Use

synchronized can realize thread synchronization and ensure thread safety. synchronized code blocks or methods allow only one thread to enter the critical region at the same time.

II. Usage

  1. Modify common methods, namely synchronization methods
  2. Modifying static methods, namely static synchronization methods
  3. Modify code blocks, that is, synchronized code blocks

3. Examples

1. Synchronization method

The code modifies the method with synchronization to start threads t0 and t1. Our expectation is that one thread enters the critical zone and another is waiting. Threads entering the critical region sleep for 2 seconds and then exit the critical region. Another thread enters the critical region again.

public class Sync {
	
	public synchronized void method() {
		System.out.println(Thread.currentThread().getName() + ": in");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out");
	}
	
	public static void main(String[] args) {
		final Sync s = new Sync();
		Thread t0 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				s.method();
			}
		});
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				s.method();
			}
		});
		t0.start();
		t1.start();
	}
	
}

Operation results:

You can see the expected result.

Now there is only one method. Let's test several methods.
public class Sync {
	
	public synchronized void method1() {
		System.out.println(Thread.currentThread().getName() + ": in method1");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method1");
	}
	
	public void method2() {
		System.out.println(Thread.currentThread().getName() + ": in method2");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method2");
	}
	
	public static void main(String[] args) {
		final Sync s = new Sync();
		Thread t0 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				s.method1();
			}
		});
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				s.method2();
			}
		});
		t0.start();
		t1.start();
	}
	
}

Now there are two methods, method1 and method2. Method1 is modified by synchronization, and method2 is a common method.

Take a look at the results of the operation:

It does not seem to affect the non-synchronized decorated method of calling objects by other threads.

So what if both methods are synchronized modifications?
public class Sync {
	
	public synchronized void method1() {
		System.out.println(Thread.currentThread().getName() + ": in method1");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method1");
	}
	
	public synchronized void method2() {
		System.out.println(Thread.currentThread().getName() + ": in method2");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method2");
	}
	
	public static void main(String[] args) {
		final Sync s = new Sync();
		Thread t0 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				s.method1();
			}
		});
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				s.method2();
			}
		});
		t0.start();
		t1.start();
	}
	
}

When we see the results, we will find that two different methods of the same object modified by synchronization can not be called at the same time.

Try different subjects again
public class Sync {
	
	public synchronized void method1() {
		System.out.println(Thread.currentThread().getName() + ": in method1");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method1");
	}
	
	public synchronized void method2() {
		System.out.println(Thread.currentThread().getName() + ": in method2");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method2");
	}
	
	public static void main(String[] args) {
		final Sync s0 = new Sync();
		final Sync s1 = new Sync();
		Thread t0 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				s0.method1();
			}
		});
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				s1.method1();
			}
		});
		t0.start();
		t1.start();
	}
	
}

From the running results, it can be seen that method1() method which calls different objects can be invoked at the same time.

So the different names of different objects still have no influence on each other.

So can we conclude that synchronized modifies common methods by locking objects, that is, object locks?

2. Static Synchronization Method

Change method1 and methd2 to static methods, and both threads call method1.

public class Sync {
	
	public static synchronized void method1() {
		System.out.println(Thread.currentThread().getName() + ": in method1");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method1");
	}
	
	public static synchronized void method2() {
		System.out.println(Thread.currentThread().getName() + ": in method2");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method2");
	}
	
	public static void main(String[] args) {
		Thread t0 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				Sync.method1();
			}
		});
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				Sync.method1();
			}
		});
		t0.start();
		t1.start();
	}
	
}

Two threads calling method1 can't enter the critical zone at the same time, only after one exits the critical zone can the other enter.

Try calling different static methods again.

public class Sync {
	
	public static synchronized void method1() {
		System.out.println(Thread.currentThread().getName() + ": in method1");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method1");
	}
	
	public static synchronized void method2() {
		System.out.println(Thread.currentThread().getName() + ": in method2");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": out method2");
	}
	
	public static void main(String[] args) {
		Thread t0 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				Sync.method1();
			}
		});
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				Sync.method2();
			}
		});
		t0.start();
		t1.start();
	}
	
}

Still the same result, the two processes cannot enter the critical zone at the same time.

synchronized static modification is to lock classes, that is, class locks.

3. Synchronized code block

Synchronized code blocks are all like this:

synchronized (...) {
	...
}

Object Lock

synchronized (this) {
	...
}

Writing like this can't be written in static methods, and the effect is similar to that of synchronous methods.

Class lock

synchronized (XXX.class) {
	...
}

XXX refers to the class name.

Writing like this can be done in both static and general methods. (1) Two kinds of writing methods can not be written as building blocks, but can be written in the construction method.

(3) Private Locks

Object lock
synchronized (lock) {
	...
}

Private locks are smaller in size and do not compete with object locks and class locks.

The code demonstrates:

public class Sync {
 	
	public Integer a = new Integer(1);
	public void method() {
		System.out.println(Thread.currentThread().getName() + ": in method");
		synchronized (a) {
			System.out.println(Thread.currentThread().getName() + ": in synchronized block");
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + ": out synchronized block");
		}
		System.out.println(Thread.currentThread().getName() + ": out moetod");
	}
	
	public static void main(String[] args) {
		final Sync s = new Sync();
		
		Thread t0 = new Thread(new Runnable() {
			@Override
			public void run() {
				s.method();
			}
		});
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				s.method();
			}
		});
		t0.start();
		t1.start();
	}
	
}

Running results show that two threads can enter the method at the same time, but not the code block contained in synchronized (a) {...}.

When the lock in synchronized {...} is a different object, the result is different.

For example, Xiao Ming and Xiao Hong can enter the room at the same time, but Xiao Ming (or Xiao Hong) must walk out of the room before entering the room again.

public class Sync {
	class Person {
		String name;
		Person(String name) {
			this.name = name;
		}
		void enterRoom() {
			System.out.println(Thread.currentThread().getName() + "-->" + name + ": I'm ready!");
			synchronized (name) {
				System.out.println(Thread.currentThread().getName() + "-->" + name + ": I'm in the room, and I'm going to stay in the room for two seconds!");
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				exitRoom();
			}
			
		}
		void exitRoom() {
			System.out.println(Thread.currentThread().getName() + "-->" + name + ": I quit the room!");
		}
	}
	public static void main(String[] args) {
		final Person p1 = new Sync().new Person("Xiao Ming");
		final Person p2 = new Sync().new Person("Xiao Ming");
		Thread t0 = new Thread(new Runnable() {
			@Override
			public void run() {
				p1.enterRoom();
			}
		});
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				p2.enterRoom();
			}
		});
		t0.start();
		t1.start();
	}
	
}

When the lock is the same object, two threads cannot enter at the same time.

Rename p2 Xiaohong

final Person p1 = new Sync().new Person("Xiao Ming");
final Person p2 = new Sync().new Person("Xiaohong");

You can see Xiao Ming Xiaohong entering the room almost at the same time, that is, the two threads are synchronized.

Tags: Java

Posted on Mon, 26 Aug 2019 23:00:25 -0700 by varghesedxb