多線程鎖——詳解


先來講什么是線程:

即:Thread和Runnable兩個類,可以實現線程

class Card extends Thread{

  //第一步,重寫父類Thread中的run方法,這樣就可以調度線程,調度線程中啟動的方法,即run方法:

  @Override

  public void run(){

    System.out.println("線程啟動...");

  }

}

為何要重寫run方法,因為多線程方法的調用過程就是這么定義的,我們任何線程的

當我們Thread類的引用被創建以后,我們可以調用start方法來啟動該線程,很有趣的是,我們應該要思考,我們start啟動完線程以后,我們的執行順序是怎么樣的?

首先,我們知道,我們的線程體方法是run,如果我們直接調用run方法,例如

public class Test{

  Thread1 t1=new Thread1();

  Thread2 t2=new Thread2();

  t1.run();

  t2.run();

}

這種情況下,我們的執行順序,是調用方法的執行順序,即先執行Thread1中的run方法,再是Thread2中的run方法

然而,這樣的調用方式,就會把我們多線程的作用給浪費了,那么該如何是好?

所以,我們才有調用Thread.start()方法,這個方法調用的目的,就是為了將我們的線程,提交至線程棧,或者線程隊列,(待考證)

 

當然上面的線程體只是做了打印的操作,對於我們的多個線程的創建並運行並沒有什么多大的影響?什么,你告訴我什么是影響?一般都一下幾種影響:

1、線程競爭 顧名思義,就是在多個任務(也叫做創建多個線程(多個線程可能都是相同的線程體,也可能是不同的線程體)並啟動)同時訪問同一個線程體的同時,對執行相同的代碼,並且同時執行,例如以下代碼

static int ii=0;

 

public Map<Integer,Object> map=new HashMap<Integer,Object>(); 

@Override

public void run(){

  while(ii<100){

    ii++;

    System.out.println("ii:" + ii + "currentThreadNo:" + Thread.currentThread().getName());

  }

}

 

public static void main(String[] args){

  for(int n=0;n<100;n++){

    new Thread(new ThreadSample()).start();

  }

}

 現在我們要啟動100個線程,對相同的線程體進行100次的任務調用,然后,我們截取前10個輸出打印,我們將發現如下:

ii:1currentThreadNo:Thread-0
ii:2currentThreadNo:Thread-2
ii:3currentThreadNo:Thread-2
ii:4currentThreadNo:Thread-2
ii:5currentThreadNo:Thread-2
ii:8currentThreadNo:Thread-2
ii:9currentThreadNo:Thread-2
ii:10currentThreadNo:Thread-3
ii:12currentThreadNo:Thread-3
ii:13currentThreadNo:Thread-3
ii:14currentThreadNo:Thread-3
ii:7currentThreadNo:Thread-0
ii:16currentThreadNo:Thread-0
ii:17currentThreadNo:Thread-0
ii:6currentThreadNo:Thread-4

 

顯然,我們看到,我們的線程輸出是從1~5之后,直接跳到8,什么意思?就是說在我們線程2調度完畢,輸出為5之后,我們線程2接下去直接調度輸出就變成了8,因為6和7已經被其他線程調度到一般,值發生了改變,於是等到我們線程0都調度輸出為17之后,這個時候,我們先前的線程4,開始輸出6了,大家看,一直等到這一刻,我們的線程4才輸出6啊,這里有個問題,就是我們的線程是不安全的,同時有多個線程一起來競爭這個資源,也或者說叫做同時有多個任務一起競爭這個資源,那么競爭完后必然會造成線程體中,各線程對於資源的爭搶

所以,我們需要對我們的線程體加鎖,怎么加鎖?給方法上,加上同步synchronized,這樣,就能夠保證我們的線程是一個安全的線程,什么是安全線程,就是意味着,我們所有一起參與競爭的任務,或者說線程,不會造成一個任務或線程調用到一半的時候,另外的任務或者線程參與進來開始調度,當我們將run方法改寫為如下后,

public synchronized void run(){...}

於是,,我們在運行一下看下我們的日志輸出是什么樣的情況:

ii:1currentThreadNo:Thread-0
ii:2currentThreadNo:Thread-0
ii:3currentThreadNo:Thread-2
ii:4currentThreadNo:Thread-2
ii:5currentThreadNo:Thread-2
ii:6currentThreadNo:Thread-2
ii:7currentThreadNo:Thread-2
ii:8currentThreadNo:Thread-2

.

.

.

ii:531currentThreadNo:Thread-3
ii:532currentThreadNo:Thread-30
ii:533currentThreadNo:Thread-17
ii:534currentThreadNo:Thread-28
ii:535currentThreadNo:Thread-24
ii:536currentThreadNo:Thread-13
ii:537currentThreadNo:Thread-26
ii:538currentThreadNo:Thread-9
ii:539currentThreadNo:Thread-22
ii:540currentThreadNo:Thread-18
ii:541currentThreadNo:Thread-14
ii:542currentThreadNo:Thread-10
ii:543currentThreadNo:Thread-5
ii:544currentThreadNo:Thread-6

 

大吃一驚,我們最終輸出的結果居然到了544,而我們同時參與並發的線程任務才只有500個,這又是為啥呢?

原來,我們沒有對run內部調用的所有代碼(我們把所有這些代碼看成一個方法,)進行加鎖操作,所以,我們需要對方法進行如下改進:

 

@Override

public void run(){

  synchronized(this){

    while(ii<500){ 

      ii++;
      queue.add(ii);
      System.out.println("ii:" + ii + "currentThreadNo:" + Thread.currentThread().getName());

    }

  }

}

 但是,當我們運行多個任務調度的時候,發現,在一個線程參與一次迭代的時候,接下去還是會有其他線程參與競爭,這樣的話,問題就來了

 

為什么我們加了鎖以后,我們的線程還是不安全,還是會有其他線程參與競爭,,,,這個問題很嚴重啊

 

於是我們將方法修改如下 :

@Override

public void run(){

  synchronized(ThreadSample.class){

    while(ii<500){ 

      ii++;
      queue.add(ii);
      System.out.println("ii:" + ii + "currentThreadNo:" + Thread.currentThread().getName());

    }

  }

}

這個時候,我們高興的發現,我們的輸出,終於是線程安全的了,就是當我們一個線程執行這個線程體的過程中,其他線程是無法參與進來的,輸出如下:

ii:1currentThreadNo:Thread-0 Tue Apr 30 15:18:50 CST 2019
ii:2currentThreadNo:Thread-0 Tue Apr 30 15:18:50 CST 2019
ii:3currentThreadNo:Thread-0 Tue Apr 30 15:18:50 CST 2019
ii:4currentThreadNo:Thread-0 Tue Apr 30 15:18:50 CST 2019

.

.

ii:497currentThreadNo:Thread-0 Tue Apr 30 15:18:50 CST 2019
ii:498currentThreadNo:Thread-0 Tue Apr 30 15:18:50 CST 2019
ii:499currentThreadNo:Thread-0 Tue Apr 30 15:18:50 CST 2019
ii:500currentThreadNo:Thread-0 Tue Apr 30 15:18:50 CST 2019

這樣,我們的線程終於安全了。

 

鎖:synchronized

 


免責聲明!

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



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