多線程總結(jié)(基礎(chǔ))

多線程與并發(fā)

多線程

線程的實(shí)現(xiàn)方法

繼承Thread類

  1. 繼承Thread類
  2. 重寫run方法
  3. start開啟線程
public class MyThread extends Thread{
    @Override
    public void run() {

        System.out.println(Thread.currentThread().getName()+"-->haha");
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.setName("thread1");
        myThread.start();
    }
}

實(shí)現(xiàn)Runnable接口

  1. 實(shí)現(xiàn)Runnable接口
  2. 創(chuàng)建Thread對象
  3. 參數(shù)為實(shí)現(xiàn)類
  4. start啟動線程
public class MyThread2 implements Runnable {
    @Override
    public void run() {
        System.out.println("hahaha");
    }

    public static void main(String[] args) {
        new Thread(new MyThread2()).start();
    }
}

實(shí)現(xiàn)Callable接口

//1. 實(shí)現(xiàn)Callable谭确,返回值類型為String
public class Thread3 implements Callable<String> {
    @Override
    // 2. 重寫call方法
    public String call() throws Exception {
        System.out.println("hahahah");
        return "我是返回值";
    }
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //3. 打開服務(wù),參數(shù)為服務(wù)個數(shù)
        ExecutorService service = Executors.newFixedThreadPool(1);
        //4. 提交執(zhí)行
        Future<String> future = service.submit(new Thread3());
        //5. 獲取返回值
        String s = future.get();
        //6. 結(jié)束服務(wù)
        service.shutdownNow();
    }
}

靜態(tài)代理模式

案例:

public class StaticProxy {
  //************測試主方法*************
    public static void main(String[] args) {
        You you = new You();
        WeddingCompany weddingCompany = new WeddingCompany(you);
        weddingCompany.marry();
    }
}
 //*************************
//結(jié)婚接口
interface Marry {
  //結(jié)婚方法
    void marry();
}
 //*************************
//真實(shí)對象實(shí)現(xiàn)結(jié)婚接口
class You implements Marry {

  //重寫結(jié)婚方法
    @Override
    public void marry() {
        System.out.println("要結(jié)婚了,哈哈哈");
    }
}
 //*************************
//代理對象實(shí)現(xiàn)結(jié)婚接口
class WeddingCompany implements Marry {
    private Marry target;
 //通過傳入?yún)?shù)的方式調(diào)用真實(shí)對象
    public WeddingCompany(Marry target) {
        this.target = target;
    }
  //重寫結(jié)婚方法
    @Override
    public void marry() {
        before();
        this.target.marry();
        after();
    }

    private void after() {
        System.out.println("收尾款");
    }

    private void before() {
        System.out.println("布置現(xiàn)場");
    }
}

核心點(diǎn):
直接使用代理對象即可,為什么代理對象可以擁有真實(shí)對象的方法我纪,因?yàn)閚ew代理對象時,傳參傳了個真實(shí)對象<跸浮流济!

線程狀態(tài)

停止線程

  • 不推薦使用JDK提供的stop() destory()廢棄方法。
  • 可以使用flag=false讓線程停止
public class Thread4 implements Runnable {
    private boolean flag = true;

    @Override
    public void run() {
        int i=0;
        while (flag) {
            System.out.println("thread4...."+i++);
        }
    }

    public void myStop() {
        this.flag = false;
    }

  //測試類
static class Test{
        public static void main(String[] args) {
            Thread4 thread4 = new Thread4();
            new Thread(thread4).start();
            for (int i = 0; i < 1000; i++) {
                System.out.println(i);
                if (i==800){
                    thread4.myStop();
                }
            }
        }
    }
}

線程休眠sleep(抱著鎖睡覺)

sleep不釋放鎖技即,其他線程必須等待它執(zhí)行完畢才能執(zhí)行

public class ThreadDemo {

  //lock對象將傳入synchronized代碼塊里著洼,為保證兩個線程搶一把鎖 
    private static Object lock = new Object();

    public static void main(String[] args) {
        new Thread(()->{
            synchronized (lock){
                try {
                    System.out.println("A休眠10秒不放棄鎖");
                    Thread.sleep(10000);
                    System.out.println("A休眠10秒醒來");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }).start();

        new Thread(()->{

            synchronized (lock){
                System.out.println("B休眠10秒不放棄鎖");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("B休眠10秒醒來");
            }
        }).start();
    }
}
A休眠10秒不放棄鎖
A休眠10秒醒來
B休眠10秒不放棄鎖
B休眠10秒醒來
或者
B休眠10秒不放棄鎖
B休眠10秒醒來
A休眠10秒不放棄鎖
A休眠10秒醒來

線程禮讓yield

public static void main(String[] args) {
        new Thread(() -> {
            System.out.println("A在執(zhí)行。而叼。身笤。");
            Thread.yield();
            System.out.println("A結(jié)束了");
        }).start();
        
        new Thread(() -> {
            System.out.println("B在執(zhí)行");
            Thread.yield();
            System.out.println("B結(jié)束了");
        }).start();
    }
A在執(zhí)行
A結(jié)束了
B在執(zhí)行
B結(jié)束了
  或者
A在執(zhí)行
B在執(zhí)行
A結(jié)束了
B結(jié)束了

線程插隊join

**注意 **:誰調(diào)用讓誰插隊

public static void main(String[] args) {
        Thread threadA=new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                System.out.println("A在執(zhí)行==》"+i);
                if (i==50){

                }
            }
        });
        threadA.start();

        Thread threadB=new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                System.out.println("B在執(zhí)行==》"+i);
                if (i==50){
                    try {
                      // 讓A線程插隊
                        threadA.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        threadB.start();
    }

線程狀態(tài)以及優(yōu)先級

  thread.getState()
  thread.setPriority(int requestedPriority)
  thread.getPriority();

守護(hù)線程

在Java中有兩類線程:User Thread(用戶線程)、Daemon Thread(守護(hù)線程)

用個比較通俗的比如葵陵,任何一個守護(hù)線程都是整個JVM中所有非守護(hù)線程的保姆:

只要當(dāng)前JVM實(shí)例中尚存在任何一個非守護(hù)線程沒有結(jié)束液荸,守護(hù)線程就全部工作;只有當(dāng)最后一個非守護(hù)線程結(jié)束時脱篙,守護(hù)線程隨著JVM一同結(jié)束工作娇钱。
Daemon的作用是為其他線程的運(yùn)行提供便利服務(wù),守護(hù)線程最典型的應(yīng)用就是 GC (垃圾回收器)涡尘,它就是一個很稱職的守護(hù)者忍弛。

User和Daemon兩者幾乎沒有區(qū)別,唯一的不同之處就在于虛擬機(jī)的離開:如果 User Thread已經(jīng)全部退出運(yùn)行了考抄,只剩下Daemon Thread存在了细疚,虛擬機(jī)也就退出了。 因?yàn)闆]有了被守護(hù)者川梅,Daemon也就沒有工作可做了疯兼,也就沒有繼續(xù)運(yùn)行程序的必要了。

 Thread daemonTread = new Thread();
  // 設(shè)定 daemonThread 為 守護(hù)線程贫途,default false(非守護(hù)線程)
 daemonThread.setDaemon(true);
 // 驗(yàn)證當(dāng)前線程是否為守護(hù)線程吧彪,返回 true 則為守護(hù)線程
 daemonThread.isDaemon();

并發(fā)

并發(fā):同一個對象被多個線程同時操作

synchronized

修飾方法

public class synTest {
    public static void main(String[] args) {
        DemoService service = new DemoService();
        TestThread testThread = new TestThread(service);
        new Thread(testThread,"線程1:").start();
        new Thread(testThread,"線程2:").start();
    }
}

class DemoService {

     synchronized public void foo1() {
        System.out.println(Thread.currentThread().getName() + "foo1開始了。丢早。姨裸。秧倾。");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "foo1結(jié)束了。傀缩。那先。。赡艰。");
    }

    synchronized public void foo2() {
        System.out.println(Thread.currentThread().getName() + "foo2開始了售淡。。慷垮。揖闸。");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "foo2結(jié)束了。料身。汤纸。。芹血。");
    }
}

class TestThread implements Runnable {
    private DemoService demoService;

    public TestThread(DemoService demoService) {
        this.demoService = demoService;
    }

    @Override
    public void run() {
        demoService.foo1();
        demoService.foo2();
    }
}

case1:foo1和foo2加鎖時輸出結(jié)果:

線程1:foo1開始了蹲嚣。。祟牲。隙畜。
線程1:foo1結(jié)束了。说贝。议惰。。乡恕。
線程1:foo2開始了言询。。傲宜。运杭。
線程1:foo2結(jié)束了。函卒。辆憔。。报嵌。
線程2:foo1開始了虱咧。。锚国。腕巡。
線程2:foo1結(jié)束了。血筑。绘沉。煎楣。。
線程2:foo2開始了车伞。转质。。帖世。
線程2:foo2結(jié)束了。沸枯。日矫。。绑榴。

case2:foo1和foo2沒加鎖時輸出結(jié)果:

線程1:foo1開始了哪轿。。翔怎。窃诉。
線程2:foo1開始了。赤套。飘痛。。
線程2:foo1結(jié)束了容握。宣脉。。剔氏。塑猖。
線程2:foo2開始了。谈跛。羊苟。。
線程1:foo1結(jié)束了感憾。蜡励。。阻桅。巍虫。
線程1:foo2開始了。鳍刷。占遥。。
線程1:foo2結(jié)束了输瓜。瓦胎。芬萍。。搔啊。
線程2:foo2結(jié)束了柬祠。。负芋。漫蛔。。

case3:foo1加鎖旧蛾,foo2沒解鎖時:

線程1:foo1開始了莽龟。。锨天。毯盈。
線程1:foo1結(jié)束了。病袄。搂赋。。益缠。
線程1:foo2開始了脑奠。。幅慌。捺信。
線程2:foo1開始了。欠痴。迄靠。。
線程2:foo1結(jié)束了喇辽。掌挚。。菩咨。吠式。
線程2:foo2開始了。抽米。特占。。
線程1:foo2結(jié)束了云茸。是目。。标捺。懊纳。
線程2:foo2結(jié)束了揉抵。。嗤疯。冤今。。

總結(jié):synchronized修飾方法時茂缚,鎖的是調(diào)用此方法的對象戏罢,即為this。查看源碼可以明白脚囊,修飾方法時候默認(rèn)使用synchronized(this)龟糕。case1可以看出,無論線程1還是線程2凑术,執(zhí)行foo1還是foo2的時候由于對象被鎖,所以調(diào)用此對象的其他線程無法進(jìn)入所意。case2則特地亂套淮逊,兩個線程隨機(jī)執(zhí)行對象方法。case3扶踊,由于foo1加鎖泄鹏,所以foo1之前期間不會被有其他線程進(jìn)入。

同步代碼塊

public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {
            new Thread(() -> {
                synchronized (list) {
                    list.add(1);
                }
            }).start();
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }

Lock

class A{
            // 使用Lock的子類ReentrantLock
        private final ReentrantLock lock=new ReentrantLock();
        public void m(){
            lock.lock();
            try {
                // 代碼塊
            }finally {
                lock.unlock();
            }
        }
    }

synchronized和Lock的區(qū)別

<img src="../myhexo/source/images/image-20210428105514117.png" alt="image-20210428105514117" style="zoom:80%;" />

線程池

public class Testpool {
    public static void main(String[] args) {
        //1. 創(chuàng)建服務(wù)秧耗,創(chuàng)建線程池
        //newFixedThreadPool 參數(shù)為線程池大小
        ExecutorService service= Executors.newFixedThreadPool(10);
        // 執(zhí)行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //2. 關(guān)閉連接
        service.shutdown();
    }
}

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println("hahahaha");
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末备籽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子分井,更是在濱河造成了極大的恐慌车猬,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尺锚,死亡現(xiàn)場離奇詭異珠闰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瘫辩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門伏嗜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來承绸,“玉大人,你說我怎么就攤上這事界轩∽腔” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長湖苞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任羔杨,我火速辦了婚禮,結(jié)果婚禮上矾端,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好寻仗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布凡壤。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上串稀,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機(jī)與錄音颤陶,去河邊找鬼帽馋。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瓢剿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼悠轩,長吁一口氣:“原來是場噩夢啊……” “哼间狂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哗蜈,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤前标,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后距潘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炼列,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年音比,在試婚紗的時候發(fā)現(xiàn)自己被綠了俭尖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡洞翩,死狀恐怖稽犁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情骚亿,我是刑警寧澤已亥,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站来屠,受9級特大地震影響虑椎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俱笛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一捆姜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧迎膜,春花似錦泥技、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至榕订,卻和暖如春店茶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卸亮。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工忽妒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓段直,卻偏偏與公主長得像吃溅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鸯檬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評論 2 355

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