JAVASE-多線程

Thread

多線程為我們解決了程序中需要并發(fā)執(zhí)行多個任務(wù)的操作隘擎,可以通過創(chuàng)建一個線程來負(fù)責(zé)執(zhí)行需要執(zhí)行的任務(wù)。創(chuàng)建線程的方式有兩種:
1:創(chuàng)建一個類來繼承Thread類货葬,在類中重寫需要執(zhí)行對應(yīng)操作的run方法

class MyThread extends Thread {
   public void run(){
     for(int i=0;i<1000;i++){
       system.out.println(11111);
    }
 }
}
//利用造型創(chuàng)建Thread
public static void main(String[] args){
  Thread t1 = new MyThread();
}
t1.start();

需要注意的是,啟動線程需要調(diào)用Thread的start方法休傍,而不是重寫的run方法蹲姐,run方法中定義了該線程需要具體做的事情,當(dāng)start方法調(diào)用后忙厌,線程納入線程調(diào)度江咳,線程調(diào)度會自動分配CPU時間片來執(zhí)行線程,線程運行時會自動調(diào)用run方法。另外婶芭,run方法是在start方法調(diào)用完畢后執(zhí)行的着饥,而不是start方法運行過程中執(zhí)行。
這種創(chuàng)建方法可以匿名類來實現(xiàn)宰掉,相對簡單

Thread t2 = new Thread(){
  public void run(){
    system.out.println("具體方法");
 }
}

這種線程創(chuàng)建方式由于以下兩點不足所以不推薦使用:
a,由于Java是單繼承的孟害,所以當(dāng)當(dāng)前類繼承了Thread類時就不能繼承其他父類來實現(xiàn)重用挪拟,如果不繼承Thread就不能作為單一線程并發(fā),這里出現(xiàn)了繼承沖突玉组。
b谎柄,由于線程類要執(zhí)行操作就必須重寫run方法,導(dǎo)致線程和執(zhí)行的任務(wù)出現(xiàn)了強耦合關(guān)系惯雳,該線程只能執(zhí)行該任務(wù)朝巫,不利于我們后續(xù)對此線程的復(fù)用,要知道我們不可能有多少任務(wù)就開多少線程石景,要盡可能的保證效率的同時減少線程數(shù)量劈猿。
2:單獨創(chuàng)建Runnable接口并重寫run方法來單獨定義任務(wù),并通過Thread實例來實現(xiàn)Runnable接口潮孽,實現(xiàn)線程和任務(wù)的解耦

Runnable r1 = new Runnable(){
  public void run(){
    system.out.println("任務(wù)一");
  }
}
Runnable r2 = new Runnable(){
  public void run(){
    system.out.println("任務(wù)二");
  }
}
Thread t = new Thread(r1);
Thread t1 = new Thread(r2);
t.start();
t1.start();

獲取當(dāng)前線程
Java當(dāng)中所有的程序都是跑在線程上的揪荣,Java提供了一個靜態(tài)方法來獲取這個線程
static Thread currentThread()
在哪個方法中運行該方法就會獲取運行該方法的線程,main方法也是靠線程運行恩商,其過程是:當(dāng)程序啟動時变逃,操作系統(tǒng)創(chuàng)建一個進(jìn)程來運行虛擬機(jī)必逆,進(jìn)程運行后會創(chuàng)建一個線程來運行main方法怠堪,進(jìn)程中至少需要一個線程。

Thread t = Thread.currentThread();
System.out.println(t);//Thread[main,5,main]

獲取線程相關(guān)信息的API

Thread main = Thread.currentThread();
//線程ID
long id = main.getId();
//線程名
String name = main.getName();
//優(yōu)先級
int priority = main.getPriority();
//是否為守護(hù)線程
boolean isDaemon = main.isDaemon();
//是否活著
boolean isAlive = main.isAlive();
//是否被中斷
boolean isInterrupted = main.isInterrupted();

線程優(yōu)先級
線程不能干預(yù)線程調(diào)度的工作名眉,即線程無法決定時間片分配給哪個線程粟矿,也不能決定分配的具體次數(shù),但可以通過更改線程優(yōu)先級來提高分配到CPU時間片的幾率损拢,線程優(yōu)先級分為10個等級陌粹,最低為1掏秩,默認(rèn)5蒙幻,最高10邮破,理論上優(yōu)先級越高獲取CPU時間片的幾率越大矫渔。

public static void main(String[] args) {
        new Thread(new Runnable(){
            
            @Override
            public void run() {
                for(int i = 0;i <10; i++){
                    Thread t = Thread.currentThread();
                    t.setPriority(Thread.MAX_PRIORITY);
                    System.out.println("max");
                }
            }
            
        }).start();
        new Thread(new Runnable(){

            @Override
            public void run() {
                for(int i = 0;i <10; i++){
                    Thread t = Thread.currentThread();
                    t.setPriority(Thread.NORM_PRIORITY);
                    System.out.println("normal");
                }
            }
            
        }).start();
        new Thread(new Runnable(){

            @Override
            public void run() {
                for(int i = 0;i <10; i++){
                    Thread t = Thread.currentThread();
                    t.setPriority(Thread.MAX_PRIORITY);
                    System.out.println("min");
                }
            }
            
        }).start();
    }

守護(hù)線程
守護(hù)線程又叫做后臺線程镊辕,當(dāng)一個進(jìn)程中的所有前臺線程都結(jié)束時丑蛤,進(jìn)程結(jié)束前會強制結(jié)束后臺線程碌补。比如Java中的GC就是一個典型的后臺線程厦章,程序運行過程中GC會定時檢查堆中是否有垃圾可以清理,當(dāng)前臺線程都結(jié)束時GC也會停止工作群发。

Thread t = new Thread(){
  public void run(){
     System.out.println("這里為后臺線程任務(wù)");
  }
};
//在啟動線程前設(shè)置為后臺線程
t.setDaemon(true);
t.start();

多線程并發(fā)的安全問題

同步鎖

當(dāng)一個程序中有很多線程的時候,會產(chǎn)生多個線程同時訪問一個方法的現(xiàn)象起愈,比如兩個人同時都想上廁所官觅,就會產(chǎn)生沖突,而程序當(dāng)中解決這個問題的方法和現(xiàn)實當(dāng)中一樣滑绒,就是排隊,而排隊的先決條件就是給廁所上一個鎖纵势,這樣即便有人想搶也進(jìn)不去。
我們利用synchronized關(guān)鍵字來給需要的方法或代碼塊上鎖才漆,例如一個方法被上鎖后就不允許多個線程同時執(zhí)行它,這個方法被稱為同步方法

class Bathroom {
  public synchronized void goToBathroom(){
    //假如一個人上廁所耗時5秒
    Thread.sleep(5000);
    System.out.println("廁所有人~");
  }
}
public static void main(String[] args){
  Bathroom bt = new Bathroom();
  Thread person1 = new Thread(){
    public void run(){
      bt.goToBathroom();
    }
  };
  Thread person2 = new Thread(){
    public void run(){
      bt.goToBathroom();
    }
  };
  person1.start();
  person2.start();
}

這兩個線程運行起來后線程調(diào)度會隨機(jī)分配時間片給他們阅虫,當(dāng)一個線程在5秒內(nèi)訪問方法的時候該方法就被上了鎖颓帝,其他線程無法訪問,只有訪問結(jié)束后其他線程才會訪問工猜。這樣就起到了排隊的效果拴泌。

有效縮小同步鎖的范圍可以在保證安全的前提下提高并發(fā)效率
比如我們?nèi)ド虉鲑I衣服箭昵,先挑選喜歡的衣服然后拿去試衣間試衣服,這兩個過程我們沒必要都排隊,只有試衣服的時候才會排隊并且關(guān)門上鎖涵但,在程序中可以這樣表示:

class Shopping{
  Thread t = Thread.currentThread();
  public void buy(){
     System.out.println(t+"正在挑選衣服~");
     Thread.sleep(5000);

     synchronized(this){
     System.out.println(t+"正在試衣服~請排隊~");
     Thread.sleep(5000);
  }
  System.out.println(t+"結(jié)賬離開~");
}

}
public class test{
  public static void main(String[] args){
    Shopping s = new Shopping();
    Thread person1 = new Thread(){
      public void run(){
        s.buy();
      }
    };
   Thread person2 = new Thread(){
      public void run(){
        s.buy();
      }
    };
    person1.start();
    person2.start();
  }
}

這樣做可以減少排隊時間塑娇,提高商場的運作效率埋涧,程序中同樣,當(dāng)許多線程同時要訪問一個方法而必須排隊時我們可以縮小同步范圍,只將方法中必須排隊執(zhí)行的代碼塊進(jìn)行上鎖次坡,而方法中其他代碼可以并發(fā)執(zhí)行,減少排隊時間淫僻。這里需要注意的是在給方法中代碼塊上鎖時要指定一個同步監(jiān)視器悯辙,通常情況下都可用this來指定击费,即當(dāng)前對象荡灾,要想同步代碼塊有效果必須保證多線程看到的鎖對象是同一個對象瓤狐。本例中同一個對象指代為同一個商場實例皆警,如果是不同的商場即不同的對象意推,也就不存在排隊或者搶的問題珊蟀,因為它們根本不搭嘎~

靜態(tài)方法的同步
當(dāng)我們給一個靜態(tài)方法加鎖的時候育灸,鎖對象就為當(dāng)前類的類對象儿子,當(dāng)JVM加載一個類的時候蒋譬,首先讀取該類的class文件儡毕,并同時創(chuàng)建一個類對象來保存該類的類信息腰湾,一個類有且只有一個類對象两残,所以靜態(tài)的同步方法一定有同步效果。

互斥鎖

互斥鎖是指最多只有一個線程可以持有的鎖。當(dāng)鎖對象相同時慈迈,如果該對象下有兩個方法或者兩段代碼以上都加了synchronized關(guān)鍵字若贮,代表這兩個方法或者代碼互斥,互斥意味著當(dāng)一個線程解鎖并執(zhí)行代碼時另外一段加鎖的代碼其他線程無法解鎖吩翻,也就無法同時運行兜看,只有當(dāng)該線程運行完畢歸還鎖后其他線程才能解鎖運行。這種情形通常出現(xiàn)在多線程訪問公共資源時狭瞎,為了避免資源被篡改或丟失细移,僅允許一個線程進(jìn)行訪問,而在訪問期間其他線程無法訪問熊锭。

class Test{
  public synchronized void methodA(){
    Thread t = Thread.currentThread();
    System.out.println(t+"正在執(zhí)行A方法~");
    Thread.sleep(5000);
    System.out.println("A方法執(zhí)行完畢弧轧!");
  }
  public synchronized void methodB(){
    Thread t = Thread.currentThread();
    System.out.println(t+"正在執(zhí)行B方法~");
    Thread.sleep(5000);
    System.out.println("B方法執(zhí)行完畢雪侥!");
  }
}

public class Lock{
  public static void main(String[] args){
    Test test = new Test();
    Thread t1 = new Thread(){
      public void run(){
        test.methodA();
      }
    };
    Thread t2 = new Thread(){
      public void run(){
        test.methodB();
      }
    };
    t1.start();
    t2.start();
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市精绎,隨后出現(xiàn)的幾起案子速缨,更是在濱河造成了極大的恐慌,老刑警劉巖代乃,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旬牲,死亡現(xiàn)場離奇詭異,居然都是意外死亡搁吓,警方通過查閱死者的電腦和手機(jī)原茅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堕仔,“玉大人擂橘,你說我怎么就攤上這事∧牵” “怎么了通贞?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長恼五。 經(jīng)常有香客問我昌罩,道長,這世上最難降的妖魔是什么唤冈? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任峡迷,我火速辦了婚禮,結(jié)果婚禮上你虹,老公的妹妹穿的比我還像新娘绘搞。我一直安慰自己,他們只是感情好傅物,可當(dāng)我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布夯辖。 她就那樣靜靜地躺著,像睡著了一般董饰。 火紅的嫁衣襯著肌膚如雪蒿褂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天卒暂,我揣著相機(jī)與錄音啄栓,去河邊找鬼。 笑死也祠,一個胖子當(dāng)著我的面吹牛昙楚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诈嘿,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼堪旧,長吁一口氣:“原來是場噩夢啊……” “哼削葱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起淳梦,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤析砸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后爆袍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體首繁,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年螃宙,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛮瞄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片所坯。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡谆扎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芹助,到底是詐尸還是另有隱情堂湖,我是刑警寧澤,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布状土,位于F島的核電站无蜂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蒙谓。R本人自食惡果不足惜斥季,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望累驮。 院中可真熱鬧酣倾,春花似錦、人聲如沸谤专。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽置侍。三九已至映之,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蜡坊,已是汗流浹背杠输。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留秕衙,地道東北人蠢甲。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像灾梦,于是被迫代替她去往敵國和親峡钓。 傳聞我的和親對象是個殘疾皇子妓笙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容