java 多線程 synchronized

程序1:

package testsynchronized;

public class Thread1 implements Runnable {

	@Override
	public void run() {
		synchronized (this) {
			for (int i = 0; i < 10; i++) {
				System.out.println(Thread.currentThread().getName()
						+ " synchronized loop " + i);
			}
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Thread1 t1 = new Thread1();
		Thread ta = new Thread(t1, "A");
		Thread tb = new Thread(t1, "B");
		ta.start();
		tb.start();
	}

}

輸出:

A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
A synchronized loop 3
A synchronized loop 4
A synchronized loop 5
A synchronized loop 6
A synchronized loop 7
A synchronized loop 8
A synchronized loop 9
B synchronized loop 0
B synchronized loop 1
B synchronized loop 2
B synchronized loop 3
B synchronized loop 4
B synchronized loop 5
B synchronized loop 6
B synchronized loop 7
B synchronized loop 8
B synchronized loop 9

因爲a先運行,b後運行,所以a先輸出,b後輸出,而且不會出現a和b併發輸出,因爲a已經獲得了Thread1的對象鎖。


程序2:

package testsynchronized;

public class Thread2 {
	public void m1() {
		synchronized (this) {
			int i = 10;
			while (i-- > 0) {
				System.out.println(Thread.currentThread().getName() + " : " + i);
				try {
					Thread.sleep(3000);
				} catch (InterruptedException ie) {
				}
			}
		}
	}

	public void m2() {
		int i = 10;
		while (i-- > 0) {
			System.out.println(Thread.currentThread().getName() + " : " + i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException ie) {
			}
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final Thread2 myt2 = new Thread2();
		Thread t1 = new Thread(new Runnable() {
			public void run() {
				myt2.m1();
			}
		}, "t1");
		Thread t2 = new Thread(new Runnable() {
			public void run() {
				myt2.m2();
			}
		}, "t2");
		t1.start();
		t2.start();
	}

}

輸出:

t2 : 9
t1 : 9
t2 : 8
t2 : 7
t2 : 6
t1 : 8
t2 : 5
t2 : 4
t1 : 7
t2 : 3
t2 : 2
t2 : 1
t2 : 0
t1 : 6
t1 : 5
t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0

這個輸出不唯一。

可以看出,當一個線程運行同步代碼塊時,另一個線程可以同時運行非同步代碼塊。


程序3:

package testsynchronized;

public class Thread3 {
	public void m1() {
		synchronized (this) {
			int i = 10;
			while (i-- > 0) {
				System.out
						.println(Thread.currentThread().getName() + " : " + i);
				try {
					Thread.sleep(500);
				} catch (InterruptedException ie) {
				}
			}
		}
	}

	public void m2() {
		synchronized (this) {
			int i = 10;
			while (i-- > 0) {
				System.out.println(Thread.currentThread().getName() + " : " + i);
				try {
					Thread.sleep(500);
				} catch (InterruptedException ie) {
				}
			}
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final Thread3 myt3 = new Thread3();
		Thread t1 = new Thread(new Runnable() {
			public void run() {
				myt3.m1();
			}
		}, "t1");
		Thread t2 = new Thread(new Runnable() {
			public void run() {
				myt3.m2();
			}
		}, "t2");
		t1.start();
		t2.start();
	}

}

輸出:

t1 : 9
t1 : 8
t1 : 7
t1 : 6
t1 : 5
t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 9
t2 : 8
t2 : 7
t2 : 6
t2 : 5
t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0

可以看出,當一個線程運行同步代碼塊時,另一個線程不能同時運行同步代碼塊。


程序4:

package testsynchronized;

public class Thread4 {
	public void m1() {
		synchronized (this) {
			int i = 5;
			while (i-- > 0) {
				System.out.println(Thread.currentThread().getName() + " : " + i);
				try {
					Thread.sleep(3000);
				} catch (InterruptedException ie) {
				}
			}
		}
	}

	public synchronized void m2() {
		int i = 5;
		while (i-- > 0) {
			System.out.println(Thread.currentThread().getName() + " : " + i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException ie) {
			}
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final Thread4 myt4 = new Thread4();
		Thread t1 = new Thread(new Runnable() {
			public void run() {
				myt4.m1();
			}
		}, "t1");
		Thread t2 = new Thread(new Runnable() {
			public void run() {
				myt4.m2();
			}
		}, "t2");
		t1.start();
		t2.start();
	}

}

輸出:

t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0

可以看出,當一個線程運行同步代碼塊時,另一個線程就不能同時運行同步方法。


程序5:

package testsynchronized;

public class Thread5 {
	class Inner {
		private void m1() {
			int i = 5;
			while (i-- > 0) {
				System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);
				try {
					Thread.sleep(500);
				} catch (InterruptedException ie) {
				}
			}
		}

		private void m2() {
			int i = 5;
			while (i-- > 0) {
				System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
				try {
					Thread.sleep(500);
				} catch (InterruptedException ie) {
				}
			}
		}
	}

	private void m1(Inner inner) {
		synchronized (inner) { // 使用對象鎖
			inner.m1();
		}
	}

	private void m2(Inner inner) {
		inner.m2();
	}

	public static void main(String[] args) {
		final Thread5 myt5 = new Thread5();
		final Inner inner = myt5.new Inner();
		Thread t1 = new Thread(new Runnable() {
			public void run() {
				myt5.m1(inner);
			}
		}, "t1");
		Thread t2 = new Thread(new Runnable() {
			public void run() {
				myt5.m2(inner);
			}
		}, "t2");
		t1.start();
		t2.start();
	}
}

輸出:

t1 : Inner.m4t1()=4
t2 : Inner.m4t2()=4
t1 : Inner.m4t1()=3
t2 : Inner.m4t2()=3
t1 : Inner.m4t1()=2
t2 : Inner.m4t2()=2
t1 : Inner.m4t1()=1
t2 : Inner.m4t2()=1
t1 : Inner.m4t1()=0
t2 : Inner.m4t2()=0

可以看到,當使用同步代碼塊時,並非要this,其他對象也可以,而且另一個線程可以同時運行飛同步代碼塊。


總結


使用synchronized就相當於取得了某個鎖,如果是多線程,最多隻有一個線程能運行同步方法,但是對於非同步方法,其他線程也能同時運行。


對於下面的代碼:

package testsynchronized;

public class Thread6 {
	private boolean a;
	private boolean b;

	public void setA(boolean a) {
		this.a = a;
	}

	public void setB(boolean b) {
		this.b = b;
	}
	
	public synchronized void setSA(boolean a) {
		this.a = a;
	}

	public synchronized void setSB(boolean b) {
		this.b = b;
	}
	
	public void setAB() {
		setSA(true);
		setSB(false);
	}
	
	public synchronized void setSAB() {
		setA(false);
		setB(true);
	}
	
	public void check() {
		System.out.println(a == b);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final Thread6 myt6 = new Thread6();
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				myt6.setSAB();
				myt6.check();
			}
		}, "t1");
		Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				myt6.setA(true);
				myt6.setB(true);
			}
		}, "t2");
		t1.start();
		t2.start();
	}

}


是否會輸出true。

理論上是有可能輸出true的,因爲兩個線程,分別調用同步方法和非同步方法。爲了輸出true,可以加些代碼:

	public static void main(String[] args) {
		final Thread6 myt6 = new Thread6();
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				myt6.setSAB();
				try {
					Thread.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				myt6.check();
			}
		}, "t1");
		Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				myt6.setA(true);
				myt6.setB(true);
			}
		}, "t2");
		t1.start();
		t2.start();
	}

這樣就輸出true了。
發佈了455 篇原創文章 · 獲贊 40 · 訪問量 137萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章