java synchronized用法

總結一下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的鎖繼續執行。

推薦博客:https://blog.csdn.net/javazejian/article/details/72828483,這篇博客講的非常好!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章