多線程運行原理和線程安全問題解決

多線程運行原理:

  • JVM執行Main方法,操作系統會開闢一道路徑(即主線程)到CPU,但是在多線程的情況下,沒啓動一個線程,相當於開闢一條到CPU的路,CPU可以自己選擇,因此,CPU的執行一般是無序的。

  • 而在內存當中,當主方法開始執行時,主方法在棧中壓棧執行,當調用start()方法後,會重新開闢一個空間,供新啓動的線程使用

線程安全問題解決

以售票問題爲例
問題:出現了重複票和不存在的票

  1. 解決方法1:使用同步代碼塊
    格式:
synchronized(鎖對象){	
	//可能出現線程安全問題的代碼塊
}

注意:
1.通過代碼塊中的鎖對象,可以使用任意的對象
2.但是必須保證多個線程使用的鎖對象是同一個
3.鎖對象作用:

  • 把同步代碼塊鎖住,只讓一個線程在同步代碼塊中執行

代碼實現:

public class RunnableImp implements Runnable {
    private int ticket=100;
    Object o=new Object();
    @Override
    public void run() {
        while(true){
            synchronized (o){
                if(ticket>0){
                    System.out.println(Thread.currentThread().getName()+"售出了第"+ticket+"張票。。。");
                    ticket--;
                }
             }
         }
     }
 }

總結:同步中的線程,沒有執行完畢不會釋放鎖,同步外的線程沒有鎖進不去同步。同步保證了只能由一個線程在同步中執行共享數據,保證了安全。缺點是程序頻繁的判斷鎖,獲取鎖,釋放鎖,程序的效率會降低

  1. 使用同步方法
    在方法上添加Synchronized關鍵字。
    定義一個同步方法,同步方法也會把方法內部的代碼鎖住,只讓一個線程執行,同步方法的鎖對象是new RunnableImpl(),也就是this
    代碼實現:
public class RunnableImpl implements Runnable {
    private int ticket=100;

    @Override
    public void run() {
        while(true){
                selticket();
        }
    }
    public synchronized void selticket(){
        if(ticket>0){
            System.out.println(Thread.currentThread().getName()+"售出了第"+ticket+"張票。。。");
            ticket--;
        }
    }
}

3 靜態同步方法.
此時鎖對象不是this,this是創建對象之後產生的,靜態方法優先於對象。靜態方法的鎖對象是本類的class屬性 --》class文件對象

代碼演示:

public class RunnableImpl implements Runnable {
    private static int ticket=100;

    @Override
    public void run() {
        while(true){
                selticketStatic();
        }
    }
    public static synchronized void selticketStatic(){
        if(ticket>0){
            System.out.println(Thread.currentThread().getName()+"售出了第"+ticket+"張票。。。");
            ticket--;
        }
    }
}

4 Lock類
使用步驟:

  1. 在成員位置創建一個ReentrantLock對象
  2. 在可能會出現安全問題的代碼前調用Lock接口中的方法Lock獲取鎖
  3. 在可能會出現安全問題的代碼後調用Lock接口中的方法unlock釋放鎖

代碼示例:

public class RunnableImp implements Runnable {
    private int ticket=100;
    Lock l=new ReentrantLock();
    @Override
    public void run() {
        while(true) {
            l.lock();
            if (ticket > 0) {
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName() + "售出了第" + ticket + "張票。。。");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    l.unlock();
                }
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章