Java基礎 線程同步

線程的同步:在編程過程中,爲了防止多線程訪問共享資源時發生衝突,Java提供了線程同步機制。所謂同步,就是指一個線程等待另一個線程操作完再繼續的情況。

線程安全:一個類很好地同步以保護它的數據,這個類就稱爲線程安全的。

線程不安全:多個線程先後更改數據造成某些線程得到的是無效數據。

概念比較抽象,通過下面的程序來解釋:

this.ticket–表達式的結果爲ticket的當前值,因此每次輸出的ticket是當前的票數。但是由輸出結果可以看到最後輸出的:“售票員B賣票.ticket = 0”。這就和之前的if(this.ticket > 0) 產生了衝突,爲什麼ticket=0,仍然能進入if循環呢?

這就是由於不同步所造成的,程序在運行過程中需要完成兩步操作:

1.判斷是否還有票

2.賣票

但是步驟1和2之間出現了延遲。假設現在只剩下最後一張票,所有線程幾乎同時進入run()方法執行,此時if判斷條件都滿足,再執行自減操作就會有錯誤。這就是線程不同步。

package com.thred;

class MyThread implements Runnable {//線程主體類
	private int ticket = 6;
	@Override
	public void run() {//理解爲線程的主方法
		for(int x = 0; x < 50; x++) {
			if(this.ticket > 0) {//賣票的條件
				try {
					Thread.sleep(1000);
				}catch(InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "賣票.ticket = " + this.ticket--);
                //this.ticket--表達式的結果爲ticket的當前值
			}
		}
	}
}
public class Test {
	public static void main(String[] args) {
		MyThread mt = new MyThread();
		new Thread(mt, "售票員A").start();
		new Thread(mt, "售票員B").start();
		new Thread(mt, "售票員C").start();
	}
}
/*
售票員A賣票.ticket = 6
售票員C賣票.ticket = 6
售票員B賣票.ticket = 5
售票員A賣票.ticket = 4
售票員C賣票.ticket = 3
售票員B賣票.ticket = 2
售票員A賣票.ticket = 1
售票員C賣票.ticket = 1
售票員B賣票.ticket = 0
*/

怎麼解決線程不同步問題?同步代碼塊,同步方法塊。解決了不同步問題,但是程序執行速度變慢,安全性高,性能降低了。

目前只是入門,只簡單的寫一下怎麼用,原理的東西等後面深入學習再補充。

同步代碼塊:使用Synchronized關鍵字定義的代碼塊,同步時需要設置一個對象鎖,一般是給當前對象this上鎖。

package com.thred;

class MyThread implements Runnable {//線程主體類
	private int ticket = 6;
	@Override
	public void run() {//理解爲線程的主方法
		for(int x = 0; x < 50; x++) {
			synchronized(this) {//同步代碼塊
				if(this.ticket > 0) {//賣票的條件
					try {
						Thread.sleep(1000);
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
System.out.println(Thread.currentThread().getName() + "賣票.ticket = " + this.ticket--);
				}
			}
		}
	}
}
public class Test {
	public static void main(String[] args) {
		MyThread mt = new MyThread();
		new Thread(mt, "售票員A").start();
		new Thread(mt, "售票員B").start();
		new Thread(mt, "售票員C").start();
	}
}
/*
售票員A賣票.ticket = 6
售票員A賣票.ticket = 5
售票員A賣票.ticket = 4
售票員A賣票.ticket = 3
售票員A賣票.ticket = 2
售票員A賣票.ticket = 1
*/

同步方法:在一個方法上使用synchronized定義,此方法稱爲同步方法。

package com.thred;

class MyThread implements Runnable {//線程主體類
	private int ticket = 6;
	@Override
	public void run() {//理解爲線程的主方法
		for(int x = 0; x < 50; x++) {
			this.sale();
		}
	}
	public synchronized void sale() {//同步方法
		if(this.ticket > 0) {//賣票的條件
			try {
				Thread.sleep(1000);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "賣票.ticket = " + this.ticket--);
		}
	}
}
public class Test {
	public static void main(String[] args) {
		MyThread mt = new MyThread();
		new Thread(mt, "售票員B").start();
		new Thread(mt, "售票員A").start();
		new Thread(mt, "售票員C").start();
	}
}
/*
售票員B賣票.ticket = 6
售票員B賣票.ticket = 5
售票員B賣票.ticket = 4
售票員B賣票.ticket = 3
售票員B賣票.ticket = 2
售票員B賣票.ticket = 1
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章