1. 程式人生 > >Java之多線程同步基礎

Java之多線程同步基礎

當前 @override nts oid [] 源代碼 and 函數 先後

java學習的道路上呢總有一些麻煩的東西需要花費一些時間去理解,比如個人認為不好搞的多線程.

線程是並列運行的

因為是並列運行,所以有時候會發生資源搶占,從而導致參數變化;

比如醬紫

package seer.線程;

public class SumArray {
    private int sum;

    //在這個地方sumArry()沒有被同步    沒有加sync...
    public int sumArray(int[] sums) {
        sum = 0;  //重置 初始化sum
        for (int i = 0; i < sums.length; i++) {
            sum 
+= sums[i]; try { Thread.sleep(10); //發生任務切換時,有意允許切換的發生(如果加了synchronized就絕對不可能發生了.) } catch (InterruptedException e) { System.out.println("線程中斷"); e.printStackTrace(); } } return sum; } }
//=========================================================================================================== class MyThread implements Runnable { Thread thrd; static SumArray sa = new SumArray(); int[] a; int answer; //構造一個線程 public MyThread(String name, int[] nums) { thrd
= new Thread(this, name); a = nums; } //創建一個工廠方法用來創建和啟動線程 public static MyThread createAndStart(String name, int[] nums) { MyThread myThrd = new MyThread(name, nums); myThrd.thrd.start(); return myThrd; } @Override public void run() { int sum; System.out.println(thrd.getName() + "啟動"); //這裏,在sa對象上對sumArray的調用進行同步 // synchronized (sa) { answer = sa.sumArray(a); System.out.println(thrd.getName() + "計算的結果是:" + answer); // } System.out.println(thrd.getName()+"結束"); } } //=========================================================================================================== //創建一個擁有main函數的類 class Sync{ public static void main(String[] args) { int[] arr = {2, 3, 2, 3, 2}; MyThread myt = MyThread.createAndStart("線程1", arr); MyThread myt1 = MyThread.createAndStart("線程2", arr); } }


線程2啟動
線程1啟動
線程1計算的結果是:22
線程2計算的結果是:22
線程1結束
線程2結束

//ps 結果是22 原因是因為有一個sleep,這樣才能更客觀的發現兩個線程的區別

創建了兩個線程,兩個線程不分先後的執行一個方法,由於線程的並行特性,會發生兩個線程同時進入一個方法的情況, 這時候就會可能會導致數據操作次數改變,從而直接影響結果.

有兩個方法:

  方法1:

    在sumArray()方法上加synchronized關鍵字,加上這個關鍵字後的sumArray()學名叫做"同步方法"

 public synchronized int sumArray(int[] sums) {
        sum = 0;  //重置 / 初始化sum
        for (int i = 0; i < sums.length; i++) {
            sum += sums[i];
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                System.out.println("線程中斷");
                e.printStackTrace();
            }
        }
        return sum;
    }

  加上synchronized ,不管在什麽樣的線程情況下,可以保證每一次只能由一個線程進入這個方法,其他線程排隊等待,直到當前線程執行完畢才可以進入.

    方法2

    使用同步語句

   
 static SumArray sa = new SumArray();

public void run() { int sum; System.out.println(thrd.getName() + "啟動"); synchronized (sa) {//這一段 answer = sa.sumArray(a); System.out.println(thrd.getName() + "計算的結果是:" + answer); } System.out.println(thrd.getName()+"結束"); }

    同步語句的基本格式:

      synchronized(ref){

        //方法體

      }

   這裏的ref是被同步對象的引用,上文代碼中就直接引用的一個普通對象

  兩種方法都可以實現方法的同步阻止多線程的環境下造成數據紊亂的情況

  那麽同步方法和同步語句的區別在哪呢?

  雖然同步方法時實現同步的一種簡單有效的方法,但這方法並不適用於所有情況,

  例如:可能需要對某些不被synchronized修改的方法進行同步.在想使用有第三方創建的類,而無法訪問源代碼時就會出現這樣的情況.

  這個時候使用同步代碼塊

  各有所需,兩種用法,作用相同.

  

Java之多線程同步基礎