Java多線程基礎(chǔ)與使用詳細(xì)篇(二)----線程生命周期與對(duì)象中的重要方法及各個(gè)屬性與處理捕獲異常

前言

繼續(xù)學(xué)習(xí)Java多線程基礎(chǔ)與使用詳細(xì)篇(一)----線程創(chuàng)建與線程停止下的知識(shí)企垦。
本篇會(huì)涉及多線程的生命周期、Thread和Object類中的重要方法詳解答恶、線程的各個(gè)屬性、
未捕獲異常如何處理具则。

一砾淌、線程的六個(gè)狀態(tài)(生命周期)
1.1 每個(gè)狀態(tài)的含義是

(1).NEW
新創(chuàng)建了一個(gè)線程對(duì)象啦撮,但還沒有調(diào)用start()方法
(2).Runnable
Java線程中將就緒(ready)和運(yùn)行中(running)兩種狀態(tài)籠統(tǒng)的稱為“運(yùn)行”。
線程對(duì)象創(chuàng)建后汪厨,其他線程(比如main線程)調(diào)用了該對(duì)象的start()方法赃春。該狀態(tài)的線程位于可運(yùn)行線程池中,等待被線程調(diào)度選中劫乱,獲取CPU的使用權(quán)织中,此時(shí)處于就緒狀態(tài)(ready)。就緒狀態(tài)的線程在獲得CPU時(shí)間片后變?yōu)檫\(yùn)行中狀態(tài)(running)衷戈。
(3).Blocked
表示線程阻塞于鎖狭吼。例如被同步代碼塊拿走了鎖后會(huì)被阻塞。
(4).Waiting
進(jìn)入該狀態(tài)的線程需要等待其他線程做出一些特定動(dòng)作(通知或中斷)脱惰。
(5).Timed Waiting
該狀態(tài)不同于WAITING搏嗡,它可以在指定的時(shí)間后自行返回。
(6).Terminated
終止(TERMINATED):表示該線程已經(jīng)執(zhí)行完畢拉一。

1.2 狀態(tài)間的轉(zhuǎn)化圖示
image.png
1.3 演示線程的NEW采盒、RUNNBALE、Terminated狀態(tài)

展示線程的NEW蔚润、RUNNABLE磅氨、Terminated狀態(tài)。即使是正在運(yùn)行嫡纠,也是Runnable狀態(tài)烦租,而不是Running。

public class NewRunnableTerminated implements Runnable {

    public static void main(String[] args) {
        Thread thread = new Thread(new NewRunnableTerminated());
        //打印出NEW的狀態(tài)
        System.out.println(thread.getState());
        thread.start();
        System.out.println(thread.getState());
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //打印出RUNNABLE的狀態(tài)除盏,即使是正在運(yùn)行叉橱,也是RUNNABLE,而不是RUNNING
        System.out.println(thread.getState());
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //打印出TERMINATED狀態(tài)
        System.out.println(thread.getState());
    }

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(i);
        }
    }
}
結(jié)果:
NEW
RUNNABLE
RUNNABLE
0
1
2
3
4
....
TERMINATED
1.4 展示Blocked者蠕,Waiting窃祝,TimedWaiting
public class BlockedWaitingTimedWaiting implements Runnable{
    public static void main(String[] args) {
        BlockedWaitingTimedWaiting runnable = new BlockedWaitingTimedWaiting();
        Thread thread1 = new Thread(runnable);
        thread1.start();
        Thread thread2 = new Thread(runnable);
        thread2.start();
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //打印出Timed_Waiting狀態(tài),因?yàn)檎趫?zhí)行Thread.sleep(1000);
        System.out.println(thread1.getState());
        //打印出BLOCKED狀態(tài)踱侣,因?yàn)閠hread2想拿得到sync()的鎖卻拿不到
        System.out.println(thread2.getState());
        try {
            Thread.sleep(1300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //打印出WAITING狀態(tài)粪小,因?yàn)閳?zhí)行了wait()
        System.out.println(thread1.getState());

    }

    @Override
    public void run() {
        syn();
    }

    private synchronized void syn() {
        try {
            Thread.sleep(1000);
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
結(jié)果:
TIMED_WAITING
BLOCKED
WAITING
1.5 阻塞狀態(tài)是什么

(1).一般習(xí)慣而言,把Blocked(被阻塞)抡句、Waiting(等待)探膊、Timed_waiting(計(jì)時(shí)等待)都稱為阻塞狀態(tài)
(2). 不僅僅是Blocked

1.6. 線程生命周期總結(jié)

線程有六種狀態(tài),生命周期是什么待榔,這些都可以看上面的含義和畫圖看出來逞壁,或者通過網(wǎng)上學(xué)習(xí)更加深入的知識(shí)。

2. Thread和Object類中線程相關(guān)方法
2.1 方法概覽
image.png
2.1 wait,notify猾担,notifAll

作用袭灯、用法:
阻塞階段
直到以下4種情況之一發(fā)生時(shí)刺下,才會(huì)被喚醒 wait
(1). 另一個(gè)線程調(diào)用這個(gè)對(duì)象的notify()方法且剛好被喚醒的是本線程绑嘹;
(2).另一個(gè)線程調(diào)用這個(gè)對(duì)象的notifyAll()方法
(3).過了wait(long timeout)規(guī)定的超時(shí)時(shí)間,如果傳入0就永久等待
(4).線程自身調(diào)用了interrupt(),也會(huì)喚醒
喚醒階段:notify notifyAll
notify 一個(gè) 橘茉,隨機(jī)
notifyall 所有
遇到中斷

2.2 wait和notify的基本用法

普通用法:
主要是閱讀代碼的執(zhí)行順序工腋,了解wait是用來釋放鎖的,用一個(gè)代碼演示,從代碼可以看出線程一是用來釋放鎖畅卓,并睡眠2毫秒擅腰,這段實(shí)踐線程二剛好喚醒鎖線程一并獲取了鎖。

public class Wait {
    public  static Object object =
            new Object();

    //線程一
    static class Thread1 extends Thread{
        @Override
        public void run() {
            synchronized (object){
                System.out.println(Thread.currentThread().getName()+"開始執(zhí)行了...");
                try {
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("線程"+Thread.currentThread().getName()+
                "獲取到了鎖翁潘。");
            }

        }
    }

    // 線程二
    static class Thread2 extends Thread{
        @Override
        public void run() {
            synchronized (object){
                object.notify();
                System.out.println("線程"+Thread.currentThread().getName()+"調(diào)用notify...");
            }

        }
    }
    public static void main(String args[]) throws InterruptedException {
        Thread1 thread1 = new Thread1();
        Thread2 thread2 = new Thread2();
        thread1.start();
        Thread.sleep(200);
        thread2.start();
    }
}
Thread-0開始執(zhí)行了...
線程Thread-1調(diào)用notify...
線程Thread-0獲取到了鎖趁冈。
2.3 notify和notifyAll

使用3個(gè)線程,線程1和線程2首先被阻塞拜马,線程3喚醒它們渗勘。notify, notifyAll。 start先執(zhí)行不代表線程先啟動(dòng)俩莽。
notify 只會(huì)喚醒一條線程旺坠,于是導(dǎo)致第二條線程沒有喚醒一直永久的等待。
notifyAll 喚醒所有的扮超。

public class WaitNotifyAll implements Runnable {

    private static final Object resourceA = new Object();


    public static void main(String[] args) throws InterruptedException {
        Runnable r = new WaitNotifyAll();
        Thread threadA = new Thread(r);
        Thread threadB = new Thread(r);
        Thread threadC = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceA) {
                    resourceA.notifyAll();
//                    resourceA.notify();
                    System.out.println("ThreadC notified.");
                }
            }
        });
        threadA.start();
        threadB.start();
//        Thread.sleep(200);
        threadC.start();
    }
    @Override
    public void run() {
        synchronized (resourceA) {
            System.out.println(Thread.currentThread().getName()+" got resourceA lock.");
            try {
                System.out.println(Thread.currentThread().getName()+" waits to start.");
                resourceA.wait();
                System.out.println(Thread.currentThread().getName()+"'s waiting to end.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
此時(shí)會(huì)獲取兩種結(jié)果
第一種是完美的執(zhí)行取刃,并不會(huì)去阻塞線程
Thread-0 got resourceA lock.
Thread-0 waits to start.
Thread-1 got resourceA lock.
Thread-1 waits to start.
ThreadC notified.
Thread-1's waiting to end.
Thread-0's waiting to end.
第二種是會(huì)出現(xiàn)阻塞現(xiàn)況
Thread-0 got resourceA lock.
Thread-0 waits to start.
ThreadC notified.
Thread-1 got resourceA lock.
Thread-1 waits to start.
Thread-0's waiting to end.
2.4 只釋放當(dāng)前monitor展示

證明wait只釋放當(dāng)前的那把鎖,只釋放當(dāng)前monitor展示出刷,每一個(gè)鎖都是一一對(duì)應(yīng)的關(guān)系璧疗。
下面是說 線程一會(huì)持有A,B對(duì)象,然后就釋放A馁龟,此時(shí)還持有B崩侠,接下來線程二是很順利的獲取A的資源,卻沒有獲取B的資源屁柏,因?yàn)锽的資源被線程一持有并沒有釋放

public class WaitNotifyReleaseOwnMonitor {

    private static volatile Object resourceA = new Object();
    private static volatile Object resourceB = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceA) {
                    System.out.println("ThreadA got resourceA lock.");
                    synchronized (resourceB) {
                        System.out.println("ThreadA got resourceB lock.");
                        try {
                            System.out.println("ThreadA releases resourceA lock.");
                            resourceA.wait();

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (resourceA) {
                    System.out.println("ThreadB got resourceA lock.");
                    System.out.println("ThreadB tries to resourceB lock.");

                    synchronized (resourceB) {
                        System.out.println("ThreadB got resourceB lock.");
                    }
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

2.5 wait啦膜、notify、notifyAll特點(diǎn)淌喻、性質(zhì)

1僧家、 必須先擁有monitor
2、 只能喚醒其中一個(gè)
3裸删、 屬于object類 ->所有對(duì)象的引入
4八拱、 類似功能的Condition wait、notify類似
5、 同時(shí)持有多個(gè)鎖的情況 -> 注意:釋放的順序->獲取的順序

2.6. 用wait/notify來實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式

EventStorage LinkedList表用來實(shí)現(xiàn)生產(chǎn)數(shù)據(jù)和存儲(chǔ)數(shù)據(jù)方法肌稻,通過生產(chǎn)者給消費(fèi)者消費(fèi)

public class ProducerConsumerModel {
    public static void main(String[] args) {
        EventStorage eventStorage = new EventStorage();
        Producer producer = new Producer(eventStorage);
        Consumer consumer = new Consumer(eventStorage);
        new Thread(producer).start();
        new Thread(consumer).start();
    }
}

class Producer implements Runnable {

    private EventStorage storage;

    public Producer(
            EventStorage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            storage.put();
        }
    }
}

class Consumer implements Runnable {

    private EventStorage storage;

    public Consumer(
            EventStorage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            storage.take();
        }
    }
}

class EventStorage {

    private int maxSize;
    private LinkedList<Date> storage;

    public EventStorage() {
        maxSize = 10;
        storage = new LinkedList<>();
    }

    public synchronized void put() {
        while (storage.size() == maxSize) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        storage.add(new Date());
        System.out.println("倉(cāng)庫(kù)里有了" + storage.size() + "個(gè)產(chǎn)品清蚀。");
        notify();
    }

    public synchronized void take() {
        while (storage.size() == 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("拿到了" + storage.poll() + ",現(xiàn)在倉(cāng)庫(kù)還剩下" + storage.size());
        notify();
    }
}
2.7 用wait和notify實(shí)現(xiàn)兩個(gè)線程交替打印0~100的奇偶數(shù)

由此發(fā)現(xiàn)為什么wait需要放在同步代碼塊中爹谭,是為了讓通信變得可靠枷邪、防止死鎖、等待的發(fā)生诺凡。如果沒有代碼塊的保護(hù)东揣,會(huì)隨時(shí)被notify切換過去。
而是sleep本身是針對(duì)自己腹泌,和其它線程關(guān)系并不大嘶卧。

public class WaitNotifyPrintOddEveWait {

    private static int count = 0;
    private static final Object lock = new Object();


    public static void main(String[] args) {
        new Thread(new TurningRunner(), "偶數(shù)").start();
        new Thread(new TurningRunner(), "奇數(shù)").start();
    }

    //1. 拿到鎖,我們就打印
    //2. 打印完凉袱,喚醒其他線程芥吟,自己就休眠
    static class TurningRunner implements Runnable {
        @Override
        public void run() {
            while (count <= 100) {
                synchronized (lock) {
                    //拿到鎖就打印
                    System.out.println(Thread.currentThread().getName() + ":" + count++);
                    lock.notify();
                    if (count <= 100) {
                        try {
                            //如果任務(wù)還沒結(jié)束,就讓出當(dāng)前的鎖专甩,并休眠
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}
2.8 為什么線程通信的方法wait(),notify()和notifyAll()被定義在Object類里钟鸵,而Sleep定義在Thread類里

1.notify()notifyAll()是屬于一個(gè)對(duì)象的,事實(shí)上就是綁定到一個(gè)對(duì)象的鎖配深,
2.wait方法是屬于Object對(duì)象携添,那調(diào)用Thrad.wait本身就不適合
3.用supend()和resume()來阻塞線程可以嗎:不推薦,推薦使用wait /notify

3.sleep方法

作用 : 我只想讓現(xiàn)場(chǎng)在預(yù)期的時(shí)間執(zhí)行篓叶,其他時(shí)候不再占用CPU資源

3.1 sleep 方法不釋放鎖

包括 synchronized和lock, 和wait不同
使用synchronized代碼演示
展示線程sleep的時(shí)候不釋放synchronized的monitor烈掠,等sleep時(shí)間到了以后,正常結(jié)束后才釋放鎖

public class SleepDontReleaseMonitor implements Runnable {

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

    @Override
    public void run() {
        syn();
    }

    private synchronized void syn() {
        System.out.println("線程" + Thread.currentThread().getName() + "獲取到了monitor缸托。");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("線程" + Thread.currentThread().getName() + "退出了同步代碼塊");
    }
}
線程Thread-0獲取到了monitor左敌。
線程Thread-0退出了同步代碼塊
線程Thread-1獲取到了monitor。
線程Thread-1退出了同步代碼塊

使用lock代碼演示
sleep不釋放lock(lock需要手動(dòng)釋放)

public class SleepDontReleaseLock implements Runnable {

    private static final Lock lock = new ReentrantLock();

    @Override
    public void run() {
        lock.lock();
        System.out.println("線程" + Thread.currentThread().getName() + "獲取到了鎖");
        try {
            Thread.sleep(5000);
            System.out.println("線程" + Thread.currentThread().getName() + "已經(jīng)蘇醒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        SleepDontReleaseLock sleepDontReleaseLock = new SleepDontReleaseLock();
        new Thread(sleepDontReleaseLock).start();
        new Thread(sleepDontReleaseLock).start();
    }
}
線程Thread-0獲取到了鎖
線程Thread-0已經(jīng)蘇醒
線程Thread-1獲取到了鎖
線程Thread-1已經(jīng)蘇醒
3.2 sleep 方法響應(yīng)中斷

sleep方法可以讓線程進(jìn)入Waiting狀態(tài)俐镐,并且不占用CPU資源矫限,但是不釋放鎖,直到規(guī)定時(shí)間佩抹,后再執(zhí)行叼风,休眠期間如果被中斷,會(huì)拋出異常并清除中斷狀態(tài)棍苹。
Thread.sleep() 方法小于0會(huì)拋出異常
TimeUnit.SECONDS.sleep() 小于不會(huì)拋出異常无宿,推薦這種

public class SleepInterrupted implements Runnable{

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new SleepInterrupted());
        thread.start();
        Thread.sleep(6500);
        thread.interrupt();
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(new Date());
            try {
                TimeUnit.HOURS.sleep(3);
                TimeUnit.MINUTES.sleep(25);
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("我被中斷了!");
                e.printStackTrace();
            }
        }
    }
}
Sat Sep 05 10:20:43 CST 2020
我被中斷了枢里!
Sat Sep 05 10:20:50 CST 2020
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
    at threadcoreknowledge.threadobjectclasscommonmethods.SleepInterrupted.run(SleepInterrupted.java:51)
    at java.lang.Thread.run(Thread.java:748)
3.3 sleep方法總結(jié)

wait/notify/sleep 異同(方法屬于哪個(gè)對(duì)象孽鸡,線程狀態(tài)怎么切換)
相同
阻塞
響應(yīng)中斷
不同
同步方法中
釋放鎖
指定時(shí)間
所屬類

4. join方法

作用: 因?yàn)樾碌木€程加入了我們蹂午,所以我們要等他執(zhí)行完再出發(fā)
用法:main等待thread1執(zhí)行完畢,注意誰(shuí)等誰(shuí)

4.1 普通用法代碼演示

演示join彬碱,注意語(yǔ)句輸出順序豆胸,會(huì)變化。

public class Join {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "執(zhí)行完畢");
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "執(zhí)行完畢");
            }
        });

        thread.start();
        thread2.start();
        System.out.println("開始等待子線程運(yùn)行完畢");
        thread.join();
        thread2.join();
        System.out.println("所有子線程執(zhí)行完畢");
    }
}
開始等待子線程運(yùn)行完畢
Thread-1執(zhí)行完畢
Thread-0執(zhí)行完畢
所有子線程執(zhí)行完畢
4.2 遇到中斷

演示join期間被中斷的效果

public class JoinInterrupt {
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mainThread.interrupt();
                    Thread.sleep(5000);
                    System.out.println("Thread1 finished.");
                } catch (InterruptedException e) {
                    System.out.println("子線程中斷");
                }
            }
        });
        thread1.start();
        System.out.println("等待子線程運(yùn)行完畢");
        try {
            thread1.join();
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName()+"主線程中斷了");
            thread1.interrupt();
        }
        System.out.println("子線程已運(yùn)行完畢");
    }
}
等待子線程運(yùn)行完畢
main主線程中斷了
子線程已運(yùn)行完畢
子線程中斷
4.3 在join期間巷疼,線程到底是什么狀態(tài)

Waiting

public class JoinThreadState {
    public static void main(String[] args) throws InterruptedException {
        Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    System.out.println(mainThread.getState());
                    System.out.println("Thread-0運(yùn)行結(jié)束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        System.out.println("等待子線程運(yùn)行完畢");
        thread.join();
        System.out.println("子線程運(yùn)行完畢");

    }
}
等待子線程運(yùn)行完畢
WAITING
Thread-0運(yùn)行結(jié)束
子線程運(yùn)行完畢
4.4 Join 原理

通過源碼可以看到Join內(nèi)部是有去調(diào)用wait方法

  public final void join() throws InterruptedException {
             join(0);
                     }
       一開始是0晚胡,休眠時(shí)間是無(wú)線,直到喚醒或者中斷或者前面線程執(zhí)行完畢皮迟,
 public final synchronized void join(long millis)
 throws InterruptedException {
 long base = System.currentTimeMillis();
 long now = 0;

 if (millis < 0) {
 throw new IllegalArgumentException("timeout value is negative");
 }

 if (millis == 0) {
 while (isAlive()) {
 wait(0);
 }
 } else {
 while (isAlive()) {
 long delay = millis - now;
 if (delay <= 0) {
 break;
 }
 wait(delay);
 now = System.currentTimeMillis() - base;
 }
 }
 }
5. yield方法

作用:釋放CPU時(shí)間片
定位:JVM不保證遵循
yield和sleep區(qū)別:是否隨時(shí)可能再次被調(diào)度

6.獲取當(dāng)前執(zhí)行線程的引用:Thread.currentThread

演示打印main, Thread-0, Thread-1

public class CurrentThread implements Runnable {

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

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
main
Thread-0
Thread-1
7.線程的各屬性總結(jié)
image.png
7.1 演示id代碼

ID從1開始搬泥,JVM運(yùn)行起來后,我們自己創(chuàng)建的線程的ID早已不是2

 public class Id {

   public static void main(String[] args) {
       Thread thread = new Thread();
       System.out.println("主線程的ID"+Thread.currentThread().getId());
       System.out.println("子線程的ID"+thread.getId());
   }
}
7.2 守護(hù)線程

1.作用:給用戶線程提供服務(wù)
2.3個(gè)特性:
1. 線程類型默認(rèn)繼承自父線程
2. 被誰(shuí)啟動(dòng)
3. 不影響退出JVM
3.守護(hù)線程和普通線程的區(qū)別
1. 整體上無(wú)區(qū)別
2. 唯一區(qū)別在于JVM 的離開

7.3 守護(hù)線程和普通線程的區(qū)別總結(jié)

1.他整體沒什么區(qū)別伏尼,區(qū)別是否會(huì)影響退出,一個(gè)為邏輯的尉尾,一個(gè)為服務(wù)我們的
2.我們是否需要給線程設(shè)置為守護(hù)線程
我們不應(yīng)該把線程設(shè)置成守護(hù)線程爆阶,會(huì)導(dǎo)致正在訪問文件期間,
就會(huì)關(guān)掉沙咏,操作的過程會(huì)強(qiáng)行的終止辨图。
開發(fā)過程中沒必要去設(shè)置。

7.4 線程優(yōu)先級(jí)
 1.10個(gè)級(jí)別肢藐,默認(rèn)5
 2.程序設(shè)計(jì)不應(yīng)依賴于優(yōu)先級(jí)
 3. 不同操作系統(tǒng)不一樣
 4. 優(yōu)先級(jí)會(huì)被操作系統(tǒng)改變
8. 未捕獲異常如何處理
8.1 為什么需要UncaughtExceptionHandler
(1).主線程可以輕松發(fā)現(xiàn)異常故河,子線程卻不行 ExceptionInChildThread######

此代碼演示,子線程會(huì)出現(xiàn)異常,但是主線程還是會(huì)繼續(xù)執(zhí)行下去

public class ExceptionInChildThread implements Runnable {

    public static void main(String[] args) {
        new Thread(new ExceptionInChildThread()).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println(i);
        }
    }

    @Override
    public void run() {
        throw new RuntimeException();
    }
}
(2).子線程異常無(wú)法用傳統(tǒng)方法捕獲

例如一下代碼:

  1. 不加try catch拋出4個(gè)異常,都帶線程名字
  2. 加了try catch,期望捕獲到第一個(gè)線程的異常吆豹,線程234不應(yīng)該運(yùn)行鱼的,希望看到打印出Caught Exception
  3. 執(zhí)行時(shí)發(fā)現(xiàn),根本沒有Caught Exception痘煤,線程234依然運(yùn)行并且拋出異常
    這樣說明不能直接捕獲的后果凑阶。
    下面是使用了手動(dòng):在每個(gè)run方法里進(jìn)行try catch
public class CantCatchDirectly implements Runnable {

    public static void main(String[] args) throws InterruptedException {
        try {
            new Thread(new CantCatchDirectly(), "MyThread-1").start();
            Thread.sleep(300);
            new Thread(new CantCatchDirectly(), "MyThread-2").start();
            Thread.sleep(300);
            new Thread(new CantCatchDirectly(), "MyThread-3").start();
            Thread.sleep(300);
            new Thread(new CantCatchDirectly(), "MyThread-4").start();
        } catch (RuntimeException e) {
            System.out.println("Caught Exception.");
        }

    }

    @Override
    public void run() {
        try {
            throw new RuntimeException();
        } catch (RuntimeException e) {
            System.out.println("Caught Exception.");
        }
    }
}
Caught Exception.
Caught Exception.
Caught Exception.
Caught Exception.
8.2 利用UncaughtExceptionHandler接口(推薦)
1. UncaughtExceptionHandler接口
2. void uncaughtException(Thread t, Throwable e)######
3. 異常處理器的調(diào)用策略

代碼示例

    public void uncaughtException(Thread t, Throwable e) {
   //  默認(rèn)情況下parent是null
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else { 
     // 調(diào)用Thread.setDefaultUncaughtExceptionHandler();
    //  方法設(shè)置的全局handler進(jìn)行處理
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
             // 全局 handler 也不存在就輸出異常棧
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }
4.實(shí)現(xiàn)自己的UncaughtExceptionHandler
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

    private String name;

    public MyUncaughtExceptionHandler(String name) {
        this.name = name;
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        Logger logger = Logger.getAnonymousLogger();
        logger.log(Level.WARNING, "線程異常,終止啦" + t.getName());
        System.out.println(name + "捕獲了異常" + t.getName() + "異常");
    }
}
5. 調(diào)用上面UncaughtExceptionHandler
public class UseOwnUncaughtExceptionHandler implements Runnable {

    public static void main(String[] args) throws InterruptedException {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕獲器1"));

        new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-1").start();
        Thread.sleep(300);
        new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-2").start();
        Thread.sleep(300);
        new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-3").start();
        Thread.sleep(300);
        new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-4").start();
    }


    @Override
    public void run() {
        throw new RuntimeException();
    }
}
警告: 線程異常衷快,終止啦MyThread-1
捕獲器1捕獲了異常MyThread-1異常
九月 05, 2020 3:16:38 下午 threadcoreknowledge.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 線程異常宙橱,終止啦MyThread-2
捕獲器1捕獲了異常MyThread-2異常
捕獲器1捕獲了異常MyThread-3異常
九月 05, 2020 3:16:38 下午 threadcoreknowledge.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 線程異常,終止啦MyThread-3
九月 05, 2020 3:16:39 下午 threadcoreknowledge.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 線程異常蘸拔,終止啦MyThread-4
捕獲器1捕獲了異常MyThread-4異常
8.4 線程未捕獲異呈χ#總結(jié)
1.Java 異常體系
image.png
2.實(shí)際工作中,如何全家處理異常调窍? 為什么要全局護(hù)理宝冕?不處理行不行

用一個(gè)全局的UncaughtExceptionHandler,我們就可以根據(jù)自己的業(yè)務(wù)處理和前端和后端日志處理

3.run方法是否可以拋出異常陨晶?如果拋出異常猬仁,線程狀態(tài)會(huì)怎樣

如果提前沒有 catch異常帝璧,就會(huì)拋出異常,線程就會(huì)終止

4. 線程中如何處理某個(gè)未處理異常湿刽?

用一個(gè)全局處理器

9.總結(jié)
大致上就把Java 多線程的八大核心后面的四個(gè)學(xué)習(xí)了解的烁,這是用看某學(xué)習(xí)視頻總結(jié)而來的個(gè)人學(xué)習(xí)文章。希望自己也能對(duì)Java多線基礎(chǔ)鞏固起來诈闺。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渴庆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子雅镊,更是在濱河造成了極大的恐慌襟雷,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仁烹,死亡現(xiàn)場(chǎng)離奇詭異耸弄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卓缰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門计呈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人征唬,你說我怎么就攤上這事捌显。” “怎么了总寒?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵扶歪,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我摄闸,道長(zhǎng)善镰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任贪薪,我火速辦了婚禮媳禁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘画切。我一直安慰自己竣稽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布霍弹。 她就那樣靜靜地躺著毫别,像睡著了一般。 火紅的嫁衣襯著肌膚如雪典格。 梳的紋絲不亂的頭發(fā)上岛宦,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音耍缴,去河邊找鬼砾肺。 笑死挽霉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的变汪。 我是一名探鬼主播侠坎,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼裙盾!你這毒婦竟也來了实胸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤番官,失蹤者是張志新(化名)和其女友劉穎庐完,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徘熔,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡门躯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了近顷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片生音。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖窒升,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慕匠,我是刑警寧澤饱须,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站台谊,受9級(jí)特大地震影響蓉媳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锅铅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一酪呻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盐须,春花似錦玩荠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至塑径,卻和暖如春女坑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背统舀。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工匆骗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劳景,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓碉就,卻偏偏與公主長(zhǎng)得像盟广,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铝噩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354