Java thread synchronization operation

synchronized

Act on object instance: lock the given object, and obtain the lock of the given object before entering the synchronization code.

Action on instance method: it is equivalent to locking the current instance and obtaining the lock of the current instance before entering the synchronization code.

For static methods: it is equivalent to locking the current class, and obtaining the lock of the current class before entering the synchronization code.

Use

Lock instance objects

public class AccountingSync implements Runnable {
	static AccountingSync instance = new AccountingSync();
	static int i = 0;

	@Override
	public void run() {
		for (int k = 0; k < 10000; k++) {
			synchronized (instance) {
				i++;
			}
		}
	}

	@Test
	public void testInteger() throws InterruptedException {
		int count = 10;
		Thread[] ts = new Thread[count];

		for (int k = 0; k < count; k++) {
			ts[k] = new Thread(instance);
		}

		// start
		for (int k = 0; k < count; k++) {
			ts[k].start();
		}

		// join
		for (int k = 0; k < count; k++) {
			ts[k].join();
		}

		System.out.println(i);
	}
}

Lock class methods

public class AccountingSync2 implements Runnable {
	static AccountingSync2 instance = new AccountingSync2();
	static int i = 0;

	public synchronized void increase() {
		i++;
	}

	@Override
	public void run() {
		for (int k = 0; k < 10000; k++) {
			increase();
		}
	}

	@Test
	public void testInteger() throws InterruptedException {
		int count = 10;
		Thread[] ts = new Thread[count];

		for (int k = 0; k < count; k++) {
			ts[k] = new Thread(instance);
		}

		// start
		for (int k = 0; k < count; k++) {
			ts[k].start();
		}

		// join
		for (int k = 0; k < count; k++) {
			ts[k].join();
		}

		System.out.println(i);
	}
}

Error demonstration of locking class methods

public class AccountingSyncBad implements Runnable {
	static int i = 0;

	public synchronized void increase() {
		i++;
	}

	@Override
	public void run() {
		for (int k = 0; k < 10000; k++) {
			increase();
		}
	}

	@Test
	public void testInteger() throws InterruptedException {
		int count = 10;
		Thread[] ts = new Thread[count];

		for (int k = 0; k < count; k++) {
			ts[k] = new Thread(new AccountingSyncBad());
		}

		// start
		for (int k = 0; k < count; k++) {
			ts[k].start();
		}

		// join
		for (int k = 0; k < count; k++) {
			ts[k].join();
		}

		System.out.println(i);
	}
}

Let's say that each instance in locking a class instance is compared to a door. In the above test method, each door has a lock, but 10 doors have 10 locks, and each thread enters a door. Can't guarantee that the critical area resource i can be accessed by only one thread at the same time

fix

@Test
public void testIntegerFix() throws InterruptedException {
  int count = 10;
  AccountingSyncBad instance = new AccountingSyncBad();
  Thread[] ts = new Thread[count];

  for (int k = 0; k < count; k++) {
    ts[k] = new Thread(instance);
  }

  // start
  for (int k = 0; k < count; k++) {
    ts[k].start();
  }

  // join
  for (int k = 0; k < count; k++) {
    ts[k].join();
  }

  System.out.println(i);
}

Lock static class methods

public class AccountingSyncClass implements Runnable {
	static int i = 0;

	public static synchronized void increase() {
		i++;
	}

	@Override
	public void run() {
		for (int k = 0; k < 10000; k++) {
			increase();
		}
	}

	@Test
	public void testInteger() throws InterruptedException {
		int count = 10;
		Thread[] ts = new Thread[count];

		for (int k = 0; k < count; k++) {
			ts[k] = new Thread(new AccountingSyncClass());
		}

		// start
		for (int k = 0; k < count; k++) {
			ts[k].start();
		}

		// join
		for (int k = 0; k < count; k++) {
			ts[k].join();
		}

		System.out.println(i);
	}
	
	@Test
	public void testIntegerFix() throws InterruptedException {
		int count = 10;
		AccountingSyncClass instance = new AccountingSyncClass();
		Thread[] ts = new Thread[count];

		for (int k = 0; k < count; k++) {
			ts[k] = new Thread(instance);
		}

		// start
		for (int k = 0; k < count; k++) {
			ts[k].start();
		}

		// join
		for (int k = 0; k < count; k++) {
			ts[k].join();
		}

		System.out.println(i);
	}
}

The testInteger method and testIntegerFix method tested above can get correct results, because adding a lock to a static class method is equivalent to the same lock used by 10 doors, ensuring that only one thread can access the critical area resource i at the same time.

Posted by mikeT on Thu, 02 Apr 2020 10:11:30 -0700