多線程----通俗易懂(第一天)

public class T {

	private int count = 10;
	private Object o = new Object();
	
	public void m() {
		synchronized(o) { //任何線程要執行下面的代碼,必須先拿到o的鎖
			count--;
			System.out.println(Thread.currentThread().getName() + " count = " + count);
		}
	}
	
}

synchronized(o) :代表任何線程要執行這行代碼都必須先拿到o對象這把鎖,只有持有o對象鎖的線程才允許執行.如果此時第二個線程進來了,必須等到第一個線程釋放了o這把鎖才

public class T {
	
	private int count = 10;
	
	public void m() {
		synchronized(this) { //任何線程要執行下面的代碼,必須先拿到this的鎖
			count--;
			System.out.println(Thread.currentThread().getName() + " count = " + count);
		}
	}
	
}

synchronized(this) :指定鎖定自身對象.只有獲取自身對象的鎖才允許進入當前方法

  • 等價於如下:
public class T {

	private int count = 10;
	
	public synchronized void m() { //等同於在方法的代碼執行時要synchronized(this)
		count--;
		System.out.println(Thread.currentThread().getName() + " count = " + count);
	}

}

直接將synchronized加在方法上,注意:synchronized不是鎖定當前方法,而是指鎖定當前對象 類似上面 synchronized(this) 的寫法

public class T {

	private static int count = 10;
	
	public synchronized static void m() { //這裏等同於synchronized(yxxy.c_004.T.class)
		count--;
		System.out.println(Thread.currentThread().getName() + " count = " + count);
	}
	
	public static void mm() {
		synchronized(T.class) { //考慮一下這裏寫synchronized(this)是否可以?
			count --;
		}
	}

}

如果synchronized鎖定的是靜態方法,則鎖定的必須是當前類的class對象.因爲靜態方法是不需要對象訪問的

public class T implements Runnable {

	private int count = 10;
	
	public /*synchronized*/ void run() { 
		count--;
		System.out.println(Thread.currentThread().getName() + " count = " + count);
	}
	
	public static void main(String[] args) {
		T t = new T();
		for(int i=0; i<5; i++) {
			new Thread(t, "THREAD" + i).start();
		}
	}
	
}

當我們起5個線程 訪問同一個對象的count值時,如果沒有加鎖,會導致count值爲10時,可能存在多個線程同時-1 多個線程修改之後的結果還是9.要解決這個問題的話,簡單的做法可以直接在方法上加一把鎖.

多線程常見問題一 :同步和非同步方法是否可以同時調用?

public class T {

	public synchronized void m1() { 
		System.out.println(Thread.currentThread().getName() + " m1 start...");
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + " m1 end");
	}
	
	public void m2() {
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + " m2 ");
	}
	
	public static void main(String[] args) {
		T t = new T();
		new Thread(t::m1, "t1").start();
		new Thread(t::m2, "t2").start();
	}
	
}

執行上述代碼塊,發現在同步代碼塊執行的時候.非同步方法還是可以執行的.

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