synchronized关键字实现同步

Java语言提供了synchronized关键字,可以给方法或代码块进行加锁,从而实现同步。

synchronized关键字取的锁都是对象锁,而不是把代码块或方法当做锁。主要有以下几种场景:

(1) 同步化类的非静态方法,取的调用该方法的对象上的对象锁;

(2) 同步化类的静态方法,取的是类的Class对象上的对象锁;

(3) 同步化代码块,synchronized(obj){...},取的是obj上的对象锁;

(4) 同步化代码块,synchronized(this),取的是当前对象上的对象锁;

(5) 同步化代码块,synchronized(类名.class),取的是类的Class对象上的对象锁。

synchronized关键字拥有锁重入功能,也就是说在使用synchronized时,当一个线程得到对象锁后,它再次请求该对象锁也是可以再次取得的。因此,在一个同步化方法/块的内部调用本类的其他同步化方法/块,是永远可以得到锁的。

当一个线程执行的代码出现异常时,其所持有的锁会自动释放,一个示例如下:

public class Main {

	public static void main(String[] args) {
		Service s = new Service();
		Thread ta = new DispatcherThread("a", s);
		Thread tb = new DispatcherThread("b", s);
		ta.start();
		try {
			Thread.sleep(1000);
		} catch (Exception e) {
			e.printStackTrace();
		}
		tb.start();
	}

	public static class DispatcherThread extends Thread {

		Service service;

		public DispatcherThread(String name, Service service) {
			super(name);
			this.service = service;
		}

		@Override
		public void run() {
			service.f();
		}

	}

	public static class Service {
		public synchronized void f() {
			System.out.println(Thread.currentThread().getName() + " start to run.");
			g();
		}

		public synchronized void g() {
			if (Thread.currentThread().getName().equals("a")) {
				throw new RuntimeException();
			}
		}
	}

}
Exception in thread "a" a start to run.
java.lang.RuntimeException
	at com.huawei.nlz.multithread.Main$Service.g(Main.java:42)
	at com.huawei.nlz.multithread.Main$Service.f(Main.java:37)
	at com.huawei.nlz.multithread.Main$DispatcherThread.run(Main.java:29)
b start to run.

可以看到,在a抛出异常后,线程b顺利进入同步化方法中。

子类覆盖父类的同步方法时,需要手动指明同步性,否则则不会被同步化。

用String常量做同步锁时,要注意字符串的常量池特性。

只要锁对象不变,只改变锁对象的属性,对同步就不会有影响。


synchronized关键字的底层实现原理:参见zejian_专家的https://blog.csdn.net/javazejian/article/details/72828483


猜你喜欢

转载自blog.csdn.net/nlznlz/article/details/79954560
今日推荐