java如何解決線程安全問題


  1. 方式一:同步代碼塊
synchroized(同步監視器的對象){
需要被同步的代碼
}
package threadtest;
//使用同步代碼塊實現Runable接口的線程 public class Ruanble {
    
    public static void main(String[] args) {
        //創建實現類的對象
        Num num=new Num();
        //將此對象作為參數傳遞給Thread類的構造器,創建Thread類的對象
        Thread thread1 =new Thread(num);
        Thread thread2 =new Thread(num);
        Thread thread3 =new Thread(num);
        //調用start()啟動創建的Thread對象
        
        thread1.setName("線程一");
        thread2.setName("線程二");
        thread3.setName("線程三");
        
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
//創建一個類實現Runable接口
class Num implements Runnable{
    int ticket=100;
    //定義同步監視器,多個線程共同使用唯一的同步監視器
    Object obj=new Object();
    //重寫run方法
    @Override
    public void run() {
    while (true) {
        synchronized (obj) {
            if (ticket>0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()  +"開始售票,票號為"+   ticket);
                ticket--;
            }else {
                break;
            }
        }
    
     }
    }
}
package threadtest;
//同步代碼塊實現繼承Thread的線程 public class ThreadTest {

    public static void main(String[] args) {
        //創建子類對象
        EvenThread e1=new EvenThread();
        EvenThread e2=new EvenThread();
        EvenThread e3=new EvenThread();
        //調用線程的start()啟動
        e1.setName("票口一");
        e2.setName("票口二");
        e3.setName("票口三");
        
        e1.start();
        e2.start();
        e3.start();
    }
    

    
}

//創建一個類繼承與Thread類
class EvenThread extends Thread{
    static int ticket=100;
    //定義同步監視器,多個線程共同使用唯一的同步監視器
    static Object obj=new Object();
    //重寫run方法
    @Override
    public void run() {
    while (true) {
        //synchronized (obj) {//方式一,確保同步監視器唯一
            synchronized (EvenThread.class) {//EvenThread.class是唯一的
            if (ticket>0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()  +"開始售票,票號為"+   ticket);
                ticket--;
            }else {
                break;
            }
        }
    
     }
    }
}

 

說明:共享數據------多個線程共同操作的數據

        需要被同步的代碼塊,紀委操作共享的代碼

        同步監視器,俗稱鎖,任何一個類都可以充當同步監視器,但是,要求多個線程共用一個監視器

  1. 方式二:同步方法:如果操作共享數據的代碼,完整的聲明在相依的方法中,着我們可以考慮將此方法作為同步方法來寫
  2. 非靜態的同步方法的默認監視器是this,不能修改
  3. 靜態的同步方法的監視器是當前類本身,不能修改
package threadtest;
//創建同步方法實現Runable的線程 public class Ruanble {
    
    public static void main(String[] args) {
        //創建實現類的對象
        Num num=new Num();
        //將此對象作為參數傳遞給Thread類的構造器,創建Thread類的對象
        Thread thread1 =new Thread(num);
        Thread thread2 =new Thread(num);
        Thread thread3 =new Thread(num);
        //調用start()啟動創建的Thread對象
        
        thread1.setName("線程一");
        thread2.setName("線程二");
        thread3.setName("線程三");
        
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
//創建一個類實現Runable接口
class Num implements Runnable{
    int ticket=100;
    //定義同步監視器,多個線程共同使用唯一的同步監視器
    Object obj=new Object();
    //重寫run方法
    @Override
    public void run() {
    while (true) {
      push();
     }
    }
    //同步方法
    public synchronized void push() {//這里有默認的同步監視器this,是唯一的
        if (ticket>0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()  +"開始售票,票號為"+   ticket);
            ticket--;
        }
    }
}

//使用同步方法的來寫繼承Thread類的

package threadtest;

public class ThreadTest {

    public static void main(String[] args) {
        //創建子類對象
        EvenThread e1=new EvenThread();
        EvenThread e2=new EvenThread();
        EvenThread e3=new EvenThread();
        //調用線程的start()啟動
        e1.setName("票口一");
        e2.setName("票口二");
        e3.setName("票口三");
        
        e1.start();
        e2.start();
        e3.start();
    }
    

    
}

//創建一個類繼承與Thread類
class EvenThread extends Thread{
    static int ticket=100;
    //定義同步監視器,多個線程共同使用唯一的同步監視器
    static Object obj=new Object();
    //重寫run方法
    @Override
    public void run() {
    while (true) {
        push();
     }
    }
    //public synchronized void push() {//此時不加static,會在new EvenThred對象是,導致同步監視器不是唯一的,故加上static,讓它先於類的創建而創建
        public synchronized static  void push(){
        if (ticket>0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()  +"開始售票,票號為"+   ticket);
            ticket--;
        }
    }
}

 方式三使用lock鎖來確保安全,見下篇博客:鏈接---->

https://www.cnblogs.com/ylblikestudyJava/p/12378013.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM