線程的同步:在編程過程中,爲了防止多線程訪問共享資源時發生衝突,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
*/