Java----線程的同步

Java----線程的同步

引入問題

在關於線程的操作時,往往會遇到線程的安全問題。
這裏我用一個例子來說明:

package com.CharlesLC_Test;

public class Window_Test {
    public static void main(String[] args) {
        Window window = new Window();
        Thread window1 = new Thread(window);
        Thread window2 = new Thread(window);
        Thread window3 = new Thread(window);
        window1.setName("窗口一");
        window2.setName("窗口二");
        window3.setName("窗口三");
        window1.start();
        window2.start();
        window3.start();

    }

}
class Window implements Runnable{
    private int tickets = 100;
    @Override
    public void run() {
        while(true) {
            if (tickets > 0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":成功取票"+tickets+"還剩下" + --tickets);
            }
            else{break;}
        }
    }
}

結果:發現窗口出現了重票
在這裏插入圖片描述
問題所在:
對多條語句只執行了一部分,還沒有執行完,另一個線程參與進來執行。導致共享數據的錯誤。

線程同步的方式

使用Synchronized.

當一個線程調用對象的一段synchronized代碼時,需要先獲取這個鎖,然後去執行相應的代碼,執行結束之後,釋放鎖。當一個線程拿到這個鎖時,其他線程不能進入被這個鎖起來的這段代碼。

同步代碼塊

使用方法:
synchronized(對象){//需要被同步的代碼;}
這裏我修改了取票這個例子中的Window類:

class Window implements Runnable{
    private int tickets = 100;
    @Override
    public void run() {
        while(true) {
        // 這裏作了改變,把這段代碼用 synchronized鎖了起來
            synchronized (this) {
                if (tickets > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":成功取票" + tickets + "還剩下" + --tickets);
                } else {
                    break;
                }
            }
        }
    }
}

結果:
在這裏插入圖片描述

同步方法:

使用方法:
public synchronized void show(String name){ }

修改過的Window類

class Window implements Runnable{
    private int tickets = 100;
    @Override
    public void run() {
        while(true) {
            show();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (tickets == 0){
                break;
            }
        }
    }

    private synchronized void show() {
        if (tickets > 0) {
            System.out.println(Thread.currentThread().getName() + ":成功取票" + tickets + "還剩下" + --tickets);
        }

    }
}

結果:
在這裏插入圖片描述

  • 當前線程的同步方法、同步代碼塊執行結束。
  • 當前線程在同步代碼塊、同步方法中遇到break、return終止了該代碼塊、該方法的繼續執行。
  • 當前線程在同步代碼塊、同步方法中出現了未處理的Error或Exception,導致異常結束。
  • 當前線程在同步代碼塊、同步方法中執行了線程對象的wait()方法,當前線程暫停,並釋放鎖。
    注意:必須確保使用同一個資源的多個線程共用一把鎖,這個非常重要,否則就無法保證共享資源的安全

使用Lock()

導入
import java.util.concurrent.locks.ReentrantLock;

使用方式:

class A{
        private final ReentrantLock lock=new ReenTrantLock();
       public void m(){
        lock.lock()
        try{
        //保證線程安全的代碼;
        finally{
        lock.unlock();
}

synchronized與Lock的對比

1.Lock是顯式鎖(手動開啓和關閉鎖,別忘記關閉鎖),synchronized是隱式鎖,出了作用域自動釋放
2.Lock只有代碼塊鎖,synchronized有代碼塊鎖和方法鎖
3.使用Lock鎖,JVM將花費較少的時間來調度線程,性能更好。並且具有更好的擴展性(提供更多的子類)

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