java synchronized用法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_22339457/article/details/82386545

总结一下synchronized的用法:

1、修饰静态方法

2、修饰实例方法

3、修饰代码块

一、首先看一下修饰静态方法和修饰实例方法的区别,直接上代码:

/*
 * synchronized:修饰实例方法/修饰静态方法
 */
public class SynchronizedTest2 {
	public static void main(String[] args)
			throws Exception {
		AccountingSyncClass accountingSyncClass = new AccountingSyncClass();
		Thread t1 = new Thread(new AccountingSyncClass());
		Thread t2 = new Thread(new AccountingSyncClass());
		t1.start();
		t2.start();
		t2.join();
		t1.join();
		System.out.println(accountingSyncClass.i);
	}

	public void getName2() {
		System.out.println(SynchronizedTest2.class.getName());
	}
}

class AccountingSyncClass implements Runnable {
	static int i = 0;
	static boolean flag = true;
	
	// 作用于静态方法,锁是当前class对象,也就是AccountingSyncClass类对应的class对象
	public static synchronized void increase() {
		i++;
	}

	// 非静态方法,锁定当前实例对象
	public synchronized void increase2() {
		i++;
	}

	@Override
	public void run() {
		for (int j = 0; j < 1000000; j++) {
//			increase();
			increase2();
		}
	}
}

1、当run()方法中调用increase2(),main方法中两个线程如果访问的是同一个AccountingSyncClass的实例对象,则答应结果为2000000,如果是两个不同的实例对象,则结果不是2000000;

2、当run()方法中调用的是increase() [synchronized修饰的静态方法],main方法启动的线程无论访问的是否是同一个AccountingSyncClass的实例对象,结果都是2000000;

3、如果一个线程A调用一个实例对象的非static synchronized方法,而线程B需要调用这个实例对象所属类的静态 synchronized方法,是允许的,不会发生互斥现象,因为访问static synchronized 方法占用的锁是当前类的class对象,而访问非静态 synchronized 方法占用的锁是当前实例对象锁

二、下面看一下synchronized如何修饰代码块,优势:比修饰整个方法更加灵活

public class SychronizedTest {
	public static boolean flag = true;
	public static StringBuffer s1 = new StringBuffer("123");

	public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable() {
			public void run() {
				while (flag) {
					synchronized (s1) {
						try {
							s1.wait();
							System.out.println("t1 awake!");
							flag = false;
						} catch (InterruptedException e) {
						}
					}
				}
			}
		}, "t1");

		Thread t2 = new Thread(new Runnable() {
			public void run() {
				synchronized (s1) {
					System.out.println(s1);
					s1.notify();
				}
			}
		}, "t2");
		t1.start();
		t2.start();
	}
}

1、flag:用来终止线程;

2、线程t1和t2启动,t1先拿到了s1的锁,调用s1.wait()方法,释放对s1的锁;

3、线程t2获得s1的锁,执行方法块,执行完成调用notify(),叫醒等待在s1对象上的其他线程(t1线程),并释放s1的锁。t2拿到s1的锁继续执行。

必须注意的地方:

1、某个对象实例内,synchronized aMethod(){}关键字可以防止多个线程访问对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法.

2、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;

3、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

4、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

    

推荐博客:https://blog.csdn.net/javazejian/article/details/72828483,这篇博客讲的非常好!

猜你喜欢

转载自blog.csdn.net/qq_22339457/article/details/82386545