Java基礎之線程安全問題

線程安全問題

線程安全爲標題

在java程序中,若是有多個線程同時運行,而且同時執行同一段代碼,若是程序每次運行的結果和單線程運行的結果是同樣的,並且其餘變量的值也和預期是同樣的,那麼這段代碼就是線程安全的。java

可是在多線程操做中也可能會有一些線程安全的問題發生。web

以賣票事例做爲說明,有100張票往外售賣,售完結束。安全

public class Tickets implements Runnable{
   //初始化票數
   private   int ticket=100;

   @Override
   public void run() {
       //賣票
       while (true){
         
               if(ticket>0){
                   try {
                       Thread.sleep(50);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println(Thread.currentThread().getName()+"正在賣:"+ticket--);
              }
      }
  }
}

 

public class TicketsTest {
   public static void main(String[] args) {
       //聲明變量
       Tickets tickets = new Tickets();

       //建立三個線程(窗口)
       Thread t1 = new Thread(tickets,"窗口1");
       Thread t2 = new Thread(tickets,"窗口2");
       Thread t3 = new Thread(tickets,"窗口3");

       //三個窗口同時買票
       t1.start();
       t2.start();
       t3.start();
  }

}

 

可是在運行結果中會發生如下這種狀況:票已經賣出,可是總數沒有減小;或者票已經售空,仍然在減票的狀況多線程

窗口3正在賣:100
窗口1正在賣:99
窗口2正在賣:100
窗口1正在賣:98
.......
窗口2正在賣:4
窗口1正在賣:2
窗口3正在賣:1
窗口2正在賣:1
窗口1正在賣:1

這類問題就稱做線程安全問題,爲了解決這個問題,能夠採起一些線程同步的措施併發

線程同步

當咱們使用多個線程訪問同一資源的時候,且多個線程中對資源有寫的操做,就容易出現線程安全問題。ide

爲了解決併發問題(線程同步問題),也就是多線程併發訪問同一個資源,對這個資源進行寫操做的問題,java中提供了線程同步(synchronized)來解決這個問題。atom

解決線程同步的方法:spa

  • 方法1:同步代碼塊線程

    • 同步代碼塊:synchronized加在代碼塊上,格式以下code

    synchronized (lock){
       //須要同步的代碼塊
      ....
    }

     

  • 方法2:同步鎖

    • 對象的同步鎖只是一個概念,能夠想象爲在對象上標記了一個鎖.

      1. 鎖對象 能夠是任意類型。

      2. 多個線程對象 要使用同一把鎖。

  • 方法3:同步方法

    • 在方法進行同步,格式以下:

     public synchronized void method(){
           //須要同步的代碼塊
          ......
      }
Lock鎖

java.util.concurrent.locks.Lock 機制提供了比synchronized代碼塊和synchronized方法更普遍的鎖定操做,同步代碼塊/同步方法具備的功能Lock都有,除此以外更強大,更體現面向對象。Lock鎖也稱同步鎖,加鎖與釋放鎖方法化了,以下:public void lock() :加同步鎖。public void unlock() :釋放同步鎖。使用以下:

public class Tickets implements Runnable{
   //初始化票數
   private   int ticket=100;
  Lock lock = new ReentrantLock();
   @Override
   public void run() {
       //賣票
       while (true){
               lock.lock();
               if(ticket>0){
                   try {
                       Thread.sleep(50);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println(Thread.currentThread().getName()+"正在賣:"+ticket--);
              }
               lock.unlock();
      }
  }
}

 

線程安全問題

線程安全爲標題

在java程序中,若是有多個線程同時運行,而且同時執行同一段代碼,若是程序每次運行的結果和單線程運行的結果是同樣的,並且其餘變量的值也和預期是同樣的,那麼這段代碼就是線程安全的。

可是在多線程操做中也可能會有一些線程安全的問題發生。

以賣票事例做爲說明,有100張票往外售賣,售完結束。

public class Tickets implements Runnable{
   //初始化票數
   private   int ticket=100;

   @Override
   public void run() {
       //賣票
       while (true){
         
               if(ticket>0){
                   try {
                       Thread.sleep(50);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println(Thread.currentThread().getName()+"正在賣:"+ticket--);
              }
      }
  }
}

 

public class TicketsTest {
   public static void main(String[] args) {
       //聲明變量
       Tickets tickets = new Tickets();

       //建立三個線程(窗口)
       Thread t1 = new Thread(tickets,"窗口1");
       Thread t2 = new Thread(tickets,"窗口2");
       Thread t3 = new Thread(tickets,"窗口3");

       //三個窗口同時買票
       t1.start();
       t2.start();
       t3.start();
  }

}

 

可是在運行結果中會發生如下這種狀況:票已經賣出,可是總數沒有減小;或者票已經售空,仍然在減票的狀況

窗口3正在賣:100
窗口1正在賣:99
窗口2正在賣:100
窗口1正在賣:98
.......
窗口2正在賣:4
窗口1正在賣:2
窗口3正在賣:1
窗口2正在賣:1
窗口1正在賣:1

這類問題就稱做線程安全問題,爲了解決這個問題,能夠採起一些線程同步的措施

線程同步

當咱們使用多個線程訪問同一資源的時候,且多個線程中對資源有寫的操做,就容易出現線程安全問題。

爲了解決併發問題(線程同步問題),也就是多線程併發訪問同一個資源,對這個資源進行寫操做的問題,java中提供了線程同步(synchronized)來解決這個問題。

解決線程同步的方法:

  • 方法1:同步代碼塊

    • 同步代碼塊:synchronized加在代碼塊上,格式以下

    synchronized (lock){
       //須要同步的代碼塊
      ....
    }

     

  • 方法2:同步鎖

    • 對象的同步鎖只是一個概念,能夠想象爲在對象上標記了一個鎖.

      1. 鎖對象 能夠是任意類型。

      2. 多個線程對象 要使用同一把鎖。

  • 方法3:同步方法

    • 在方法進行同步,格式以下:

     public synchronized void method(){
           //須要同步的代碼塊
          ......
      }
Lock鎖

java.util.concurrent.locks.Lock 機制提供了比synchronized代碼塊和synchronized方法更普遍的鎖定操做,同步代碼塊/同步方法具備的功能Lock都有,除此以外更強大,更體現面向對象。Lock鎖也稱同步鎖,加鎖與釋放鎖方法化了,以下:public void lock() :加同步鎖。public void unlock() :釋放同步鎖。使用以下:

public class Tickets implements Runnable{
   //初始化票數
   private   int ticket=100;
  Lock lock = new ReentrantLock();
   @Override
   public void run() {
       //賣票
       while (true){
               lock.lock();
               if(ticket>0){
                   try {
                       Thread.sleep(50);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println(Thread.currentThread().getName()+"正在賣:"+ticket--);
              }
               lock.unlock();
      }
  }
}
相關文章
相關標籤/搜索