Java多線程:線程的同步與死鎖

在多線程的處理之中,可以利用Runnable描述多個線程操作的資源,而Thread描述每一個線程對象,於是當多個線程訪問同一資源的時候,如果處理不當就會產生數據的錯誤操作。

同步問題的引出

範例:創建若干個線程對象實現賣票操作

class MyThread implements Runnable{
	private int ticket = 10;
	
	public void run() {
		while(true) {
			if(this.ticket > 0) {
				try {
					Thread.sleep(100);	// 模擬網絡延遲操作
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " " + this.ticket--);
			}
			else {
				System.out.println("無票");
				break;
			}
		}
	}
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "窗口1").start();
		new Thread(mt, "窗口2").start();
		new Thread(mt, "窗口3").start();
		
		
	}
}

 

當有延遲的時候就能很輕易地看到問題所在

解決同步問題的關鍵是鎖,指的是當某一個線程執行操作的時候,其他線程外面等待。

使用synchronized關鍵字可以定義同步方法或者同步代碼塊;在同步代碼塊的操作裏面的代碼同一時間只允許一個線程執行。

1.利用同步代碼塊進行處理

synchronized(同步對象){

同步代碼操作;

}

一般要進行同步對象處理的時候可以採用當前對象this進行同步。

範例:利用同步代碼塊解決數據同步訪問問題

class MyThread implements Runnable{
	private int ticket = 10;
	
	public void run() {
		while(true) {
			synchronized(this) {	// 同步代碼塊
				if(this.ticket > 0) {
					try {
						Thread.sleep(100);	// 模擬網絡延遲操作
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + " " + this.ticket--);
				}
				else {
					System.out.println("無票");
					break;
				}
			}
		}
	}
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "窗口1").start();
		new Thread(mt, "窗口2").start();
		new Thread(mt, "窗口3").start();
	}
}

加入同步之後,雖然不會再出現數據上出錯的問題,但是程序的整體行能下降了。

2.利用同步方法解決:只需要再方法定義上使用synchronized關鍵字即可

class MyThread implements Runnable{
	private int ticket = 10;
	
	public synchronized boolean sale() {
		if(this.ticket > 0) {
			try {
				Thread.sleep(100);	// 模擬網絡延遲操作
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + " " + this.ticket--);
			return true;
		}
		else {
			System.out.println("無票");
			return false;
		}
	}
	@Override
	public void run() {
		while(true) {
			if(!this.sale()) {
				break;
			}
		}
	}
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "窗口1").start();
		new Thread(mt, "窗口2").start();
		new Thread(mt, "窗口3").start();
	}
}

使用同步代碼塊和同步方法並沒有多大差別,但是再Java類庫許多類上的同步處理都是用的是同步方法。

死鎖

死鎖是再進行多線程同步處理中有可能出現的問題。所謂的死鎖指的是若干個線程彼此互相等待的狀態。

範例:

package threads;

class test1{
	public synchronized void func(test2 t2) {
		System.out.println("我是test1,需要一個test2的對象");
		t2.get();
	}
	public synchronized void get() {
		System.out.println("我是test1,得到了一個test2的對象");
	}
}

class test2{
	public synchronized void func(test1 t1) {
		System.out.println("我是test2, 需要一個test1的對象");
		t1.get();
	}
	public synchronized void get() {
		System.out.println("我是test2,得到了一個test1的對象");
	}
}

public class DeadLock implements Runnable{
	private test1 t1 = new test1();
	private test2 t2 = new test2();
	public DeadLock() {
		new Thread(this).start();	// 新啓動一個線程
		t2.func(t1);
	}
	@Override
	public void run() {
		t1.func(t2);
	}

	public static void main(String[] args) {
		new DeadLock();
		
	}

}

造成死鎖的原因是互相等待。

若干個線程訪問同一資源時一定要進行同步處理,而過多的同步處理會造成死鎖。

死鎖是同步引起的。

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