一. 線程同步(synchronized)
(1)什麼是線程同步:就是同一個線程操作同一個資源。如果線程不同步就是引發線程安全問題。
(2)如果同時有多個線程操作同一個資源,就會帶來問題,如何避免問題的產生,可以使用互斥鎖(synchronized),這是一個關鍵字。作用在同一份資源上時,給這個資源加上一把鎖,你其他線程不許進來,等我處理結束後再說。
舉個線程不安全的例子:
package thread;
public class Test2 {
public static class Bus extends Thread{
int tickets=50;
@Override
public void run() {
while(true){
String name=Thread.currentThread().getName();
if(tickets>=1){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name+"售出"+tickets--+"號座位");
}
}
}
}
public static void main(String[] args) {
Bus bus=new Bus();
Thread window1 =new Thread(bus);
window1.setName("window1");
window1.start();
Thread window2 =new Thread(bus);
window2.setName("window2");
window2.start();
Thread window3 =new Thread(bus);
window3.setName("window3");
window3.start();
}
}
從打印結果可以看出,不僅出現了重複座位,而且還出現了 0 號座位,存在極大的bug。出現bug的原因:多個線程參與同一個數據的操作,如上代碼中,多個線程同時賣50張票,卻沒有給操作同一個資源加鎖,就會出現這種bug。
(3)解決方法
- 同步代碼塊
修改 run(),添加 synchronized(Object obj) 關鍵字。這裏一般傳入 this ,this 即 Bus 類的對象。
public static class Bus extends Thread{
int tickets=50;
@Override
public void run() {
while(true){
String name=Thread.currentThread().getName();
synchronized (this) {
if(tickets>=1){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"售出"+tickets--+"號座位");
}
}
}
}
}
- 同步方法
public static class Bus extends Thread{
int tickets=50;
boolean flag=true;
@Override
public void run() {
while(flag){
sell();
}
}
public synchronized void sell(){
String name=Thread.currentThread().getName();
if(tickets>=1){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name+"售出"+tickets--+"號座位");
flag=true;
}else{
flag=false;
}
}
}