24.01_多線程(多線程的引入)

###24.01_多線程(多線程的引入)(了解)

* 1.什么是線程

????* 線程是程序執(zhí)行的一條路徑, 一個(gè)進(jìn)程中可以包含多條線程

????* 多線程并發(fā)執(zhí)行可以提高程序的效率, 可以同時(shí)完成多項(xiàng)工作

* 2.多線程的應(yīng)用場(chǎng)景

????* 紅蜘蛛同時(shí)共享屏幕給多個(gè)電腦

????* 迅雷開啟多條線程一起下載

????* QQ同時(shí)和多個(gè)人一起視頻

????* 服務(wù)器同時(shí)處理多個(gè)客戶端請(qǐng)求


###24.02_多線程(多線程并行和并發(fā)的區(qū)別)(了解)

* 并行就是兩個(gè)任務(wù)同時(shí)運(yùn)行,就是甲任務(wù)進(jìn)行的同時(shí),乙任務(wù)也在進(jìn)行。(需要多核CPU)

* 并發(fā)是指兩個(gè)任務(wù)都請(qǐng)求運(yùn)行,而處理器只能按受一個(gè)任務(wù),就把這兩個(gè)任務(wù)安排輪流進(jìn)行,由于時(shí)間間隔較短,使人感覺兩個(gè)任務(wù)都在運(yùn)行。

* 比如我跟兩個(gè)網(wǎng)友聊天,左手操作一個(gè)電腦跟甲聊,同時(shí)右手用另一臺(tái)電腦跟乙聊天,這就叫并行。

* 如果用一臺(tái)電腦我先給甲發(fā)個(gè)消息,然后立刻再給乙發(fā)消息,然后再跟甲聊,再跟乙聊。這就叫并發(fā)。


###24.03_多線程(Java程序運(yùn)行原理和JVM的啟動(dòng)是多線程的嗎)(了解)

* A:Java程序運(yùn)行原理

????* Java命令會(huì)啟動(dòng)java虛擬機(jī),啟動(dòng)JVM,等于啟動(dòng)了一個(gè)應(yīng)用程序,也就是啟動(dòng)了一個(gè)進(jìn)程。該進(jìn)程會(huì)自動(dòng)啟動(dòng)一個(gè) “主線程” ,然后主線程去調(diào)用某個(gè)類的 main 方法。


* B:JVM的啟動(dòng)是多線程的嗎

????* JVM啟動(dòng)至少啟動(dòng)了垃圾回收線程和主線程,所以是多線程的。


###24.04_多線程(多線程程序?qū)崿F(xiàn)的方式1)(掌握)

* 1.繼承Thread

????* 定義類繼承Thread

????* 重寫run方法

????* 把新線程要做的事寫在run方法中

????* 創(chuàng)建線程對(duì)象

????* 開啟新線程, 內(nèi)部會(huì)自動(dòng)執(zhí)行run方法

????*


????????????public class Demo2_Thread {


????????????????/**

?????????????????* @param args

?????????????????*/

????????????????public static void main(String[] args) {

????????????????????MyThread mt = new MyThread();?????????????????????????? //4,創(chuàng)建自定義類的對(duì)象

????????????????????mt.start();???????????????????????????????????????????? //5,開啟線程


????????????????????for(int i = 0; i < 3000; i++) {

????????????????????????System.out.println("bb");

????????????????????}

????????????????}


????????????}

????????????class MyThread extends Thread {???????????????????????????????? //1,定義類繼承Thread

????????????????public void run() {???????????????????????????????????????? //2,重寫run方法

????????????????????for(int i = 0; i < 3000; i++) {????????????????????????? //3,將要執(zhí)行的代碼,寫在run方法中

????????????????????????System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");

????????????????????}

????????????????}

????????????}


###24.05_多線程(多線程程序?qū)崿F(xiàn)的方式2)(掌握)

* 2.實(shí)現(xiàn)Runnable

????* 定義類實(shí)現(xiàn)Runnable接口

????* 實(shí)現(xiàn)run方法

????* 把新線程要做的事寫在run方法中

????* 創(chuàng)建自定義的Runnable的子類對(duì)象

????* 創(chuàng)建Thread對(duì)象, 傳入Runnable

????* 調(diào)用start()開啟新線程, 內(nèi)部會(huì)自動(dòng)調(diào)用Runnable的run()方法


????????????public class Demo3_Runnable {

????????????????/**

?????????????????* @param args

?????????????????*/

????????????????public static void main(String[] args) {

????????????????????MyRunnable mr = new MyRunnable();?????????????????????? //4,創(chuàng)建自定義類對(duì)象

????????????????????//Runnable target = new MyRunnable();

????????????????????Thread t = new Thread(mr);????????????????????????????? //5,將其當(dāng)作參數(shù)傳遞給Thread的構(gòu)造函數(shù)

????????????????????t.start();????????????????????????????????????????????? //6,開啟線程


????????????????????for(int i = 0; i < 3000; i++) {

????????????????????????System.out.println("bb");

????????????????????}

????????????????}

????????????}


????????????class MyRunnable implements Runnable {????????????????????????? //1,自定義類實(shí)現(xiàn)Runnable接口

????????????????@Override

????????????????public void run() {???????????????????????????????????????? //2,重寫run方法

????????????????????for(int i = 0; i < 3000; i++) {????????????????????????? //3,將要執(zhí)行的代碼,寫在run方法中

????????????????????????System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");

????????????????????}

????????????????}


????????????}


###24.06_多線程(實(shí)現(xiàn)Runnable的原理)(了解)

* 查看源碼

????* 1,看Thread類的構(gòu)造函數(shù),傳遞了Runnable接口的引用

????* 2,通過init()方法找到傳遞的target給成員變量的target賦值

????* 3,查看run方法,發(fā)現(xiàn)run方法中有判斷,如果target不為null就會(huì)調(diào)用Runnable接口子類對(duì)象的run方法


###24.07_多線程(兩種方式的區(qū)別)(掌握)

* 查看源碼的區(qū)別:

????* a.繼承Thread : 由于子類重寫了Thread類的run(), 當(dāng)調(diào)用start()時(shí), 直接找子類的run()方法

????* b.實(shí)現(xiàn)Runnable : 構(gòu)造函數(shù)中傳入了Runnable的引用, 成員變量記住了它, start()調(diào)用run()方法時(shí)內(nèi)部判斷成員變量Runnable的引用是否為空, 不為空編譯時(shí)看的是Runnable的run(),運(yùn)行時(shí)執(zhí)行的是子類的run()方法


* 繼承Thread

????* 好處是:可以直接使用Thread類中的方法,代碼簡(jiǎn)單

????* 弊端是:如果已經(jīng)有了父類,就不能用這種方法

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

????* 好處是:即使自己定義的線程類有了父類也沒關(guān)系,因?yàn)橛辛烁割愐部梢詫?shí)現(xiàn)接口,而且接口是可以多實(shí)現(xiàn)的

????* 弊端是:不能直接使用Thread中的方法需要先獲取到線程對(duì)象后,才能得到Thread的方法,代碼復(fù)雜

###24.08_多線程(匿名內(nèi)部類實(shí)現(xiàn)線程的兩種方式)(掌握)

* 繼承Thread類


????????new Thread() {????????????????????????????????????????????????? //1,new 類(){}繼承這個(gè)類

????????????public void run() {???????????????????????????????????????? //2,重寫run方法

????????????????for(int i = 0; i < 3000; i++) {????????????????????????? //3,將要執(zhí)行的代碼,寫在run方法中

????????????????????System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");

????????????????}

????????????}

????????}.start();

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


????????new Thread(new Runnable(){????????????????????????????????????? //1,new 接口(){}實(shí)現(xiàn)這個(gè)接口

????????????public void run() {???????????????????????????????????????? //2,重寫run方法

????????????????for(int i = 0; i < 3000; i++) {????????????????????????? //3,將要執(zhí)行的代碼,寫在run方法中

????????????????????System.out.println("bb");

????????????????}

????????????}

????????}).start();


###24.09_多線程(獲取名字和設(shè)置名字)(掌握)

* 1.獲取名字

????* 通過getName()方法獲取線程對(duì)象的名字

* 2.設(shè)置名字

????* 通過構(gòu)造函數(shù)可以傳入String類型的名字

????*

????????????new Thread("xxx") {

????????????????public void run() {

????????????????????for(int i = 0; i < 1000; i++) {

????????????????????????System.out.println(this.getName() + "....aaaaaaaaaaaaaaaaaaaaaaa");

????????????????????}

????????????????}

????????????}.start();


????????????new Thread("yyy") {

????????????????public void run() {

????????????????????for(int i = 0; i < 1000; i++) {

????????????????????????System.out.println(this.getName() + "....bb");

????????????????????}

????????????????}

????????????}.start();

????* 通過setName(String)方法可以設(shè)置線程對(duì)象的名字

????*

????????????Thread t1 = new Thread() {

????????????????public void run() {

????????????????????for(int i = 0; i < 1000; i++) {

????????????????????????System.out.println(this.getName() + "....aaaaaaaaaaaaaaaaaaaaaaa");

????????????????????}

????????????????}

????????????};


????????????Thread t2 = new Thread() {

????????????????public void run() {

????????????????????for(int i = 0; i < 1000; i++) {

????????????????????????System.out.println(this.getName() + "....bb");

????????????????????}

????????????????}

????????????};

????????????t1.setName("芙蓉姐姐");

????????????t2.setName("鳳姐");


????????????t1.start();

????????????t2.start();


###24.10_多線程(獲取當(dāng)前線程的對(duì)象)(掌握)

* Thread.currentThread(), 主線程也可以獲取

????*

????????????new Thread(new Runnable() {

????????????????public void run() {

????????????????????for(int i = 0; i < 1000; i++) {

????????????????????????System.out.println(Thread.currentThread().getName() + "...aaaaaaaaaaaaaaaaaaaaa");

????????????????????}

????????????????}

????????????}).start();


????????????new Thread(new Runnable() {

????????????????public void run() {

????????????????????for(int i = 0; i < 1000; i++) {

????????????????????????System.out.println(Thread.currentThread().getName() + "...bb");

????????????????????}

????????????????}

????????????}).start();

????????????Thread.currentThread().setName("我是主線程");??????????????????? //獲取主函數(shù)線程的引用,并改名字

????????????System.out.println(Thread.currentThread().getName());?????? //獲取主函數(shù)線程的引用,并獲取名字

###24.11_多線程(休眠線程)(掌握)

* Thread.sleep(毫秒,納秒), 控制當(dāng)前線程休眠若干毫秒1秒= 1000毫秒 1秒 = 1000 * 1000 * 1000納秒 1000000000


????????????new Thread() {

????????????????public void run() {

????????????????????for(int i = 0; i < 10; i++) {

????????????????????????System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa");

????????????????????????try {

????????????????????????????Thread.sleep(10);

????????????????????????} catch (InterruptedException e) {

????????????????????????????e.printStackTrace();

????????????????????????}

????????????????????}

????????????????}

????????????}.start();


????????????new Thread() {

????????????????public void run() {

????????????????????for(int i = 0; i < 10; i++) {

????????????????????????System.out.println(getName() + "...bb");

????????????????????????try {

????????????????????????????Thread.sleep(10);

????????????????????????} catch (InterruptedException e) {

????????????????????????????e.printStackTrace();

????????????????????????}

????????????????????}

????????????????}

????????????}.start();

###24.12_多線程(守護(hù)線程)(掌握)

* setDaemon(), 設(shè)置一個(gè)線程為守護(hù)線程, 該線程不會(huì)單獨(dú)執(zhí)行, 當(dāng)其他非守護(hù)線程都執(zhí)行結(jié)束后, 自動(dòng)退出

????*

????????????Thread t1 = new Thread() {

????????????????public void run() {

????????????????????for(int i = 0; i < 50; i++) {

????????????????????????System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa");

????????????????????????try {

????????????????????????????Thread.sleep(10);

????????????????????????} catch (InterruptedException e) {

????????????????????????????e.printStackTrace();

????????????????????????}

????????????????????}

????????????????}

????????????};


????????????Thread t2 = new Thread() {

????????????????public void run() {

????????????????????for(int i = 0; i < 5; i++) {

????????????????????????System.out.println(getName() + "...bb");

????????????????????????try {

????????????????????????????Thread.sleep(10);

????????????????????????} catch (InterruptedException e) {

????????????????????????????e.printStackTrace();

????????????????????????}

????????????????????}

????????????????}

????????????};


????????????t1.setDaemon(true);???????????????????? //將t1設(shè)置為守護(hù)線程


????????????t1.start();

????????????t2.start();

###24.13_多線程(加入線程)(掌握)

* join(), 當(dāng)前線程暫停, 等待指定的線程執(zhí)行結(jié)束后, 當(dāng)前線程再繼續(xù)

* join(int), 可以等待指定的毫秒之后繼續(xù)

????*

????????????final Thread t1 = new Thread() {

????????????????public void run() {

????????????????????for(int i = 0; i < 50; i++) {

????????????????????????System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa");

????????????????????????try {

????????????????????????????Thread.sleep(10);

????????????????????????} catch (InterruptedException e) {

????????????????????????????e.printStackTrace();

????????????????????????}

????????????????????}

????????????????}

????????????};


????????????Thread t2 = new Thread() {

????????????????public void run() {

????????????????????for(int i = 0; i < 50; i++) {

????????????????????????if(i == 2) {

????????????????????????????try {

????????????????????????????????//t1.join();??????????????????????? //插隊(duì),加入

????????????????????????????????t1.join(30);??????????????????????? //加入,有固定的時(shí)間,過了固定時(shí)間,繼續(xù)交替執(zhí)行

????????????????????????????????Thread.sleep(10);

????????????????????????????} catch (InterruptedException e) {


????????????????????????????????e.printStackTrace();

????????????????????????????}

????????????????????????}

????????????????????????System.out.println(getName() + "...bb");


????????????????????}

????????????????}

????????????};


????????????t1.start();

????????????t2.start();

###24.14_多線程(禮讓線程)(了解)

* yield讓出cpu


###24.15_多線程(設(shè)置線程的優(yōu)先級(jí))(了解)

* setPriority()設(shè)置線程的優(yōu)先級(jí)


###24.16_多線程(同步代碼塊)(掌握)

* 1.什么情況下需要同步

????* 當(dāng)多線程并發(fā), 有多段代碼同時(shí)執(zhí)行時(shí), 我們希望某一段代碼執(zhí)行的過程中CPU不要切換到其他線程工作. 這時(shí)就需要同步.

????* 如果兩段代碼是同步的, 那么同一時(shí)間只能執(zhí)行一段, 在一段代碼沒執(zhí)行結(jié)束之前, 不會(huì)執(zhí)行另外一段代碼.

* 2.同步代碼塊

????* 使用synchronized關(guān)鍵字加上一個(gè)鎖對(duì)象來定義一段代碼, 這就叫同步代碼塊

????* 多個(gè)同步代碼塊如果使用相同的鎖對(duì)象, 那么他們就是同步的


????????????class Printer {

????????????????Demo d = new Demo();

????????????????public static void print1() {

????????????????????synchronized(d){??????????????? //鎖對(duì)象可以是任意對(duì)象,但是被鎖的代碼需要保證是同一把鎖,不能用匿名對(duì)象

????????????????????????System.out.print("黑");

????????????????????????System.out.print("馬");

????????????????????????System.out.print("程");

????????????????????????System.out.print("序");

????????????????????????System.out.print("員");

????????????????????????System.out.print("\r\n");

????????????????????}

????????????????}


????????????????public static void print2() {??

????????????????????synchronized(d){???

????????????????????????System.out.print("傳");

????????????????????????System.out.print("智");

????????????????????????System.out.print("播");

????????????????????????System.out.print("客");

????????????????????????System.out.print("\r\n");

????????????????????}

????????????????}

????????????}

###24.17_多線程(同步方法)(掌握)

* 使用synchronized關(guān)鍵字修飾一個(gè)方法, 該方法中所有的代碼都是同步的


????????class Printer {

????????????public static void print1() {

????????????????synchronized(Printer.class){??????????????? //鎖對(duì)象可以是任意對(duì)象,但是被鎖的代碼需要保證是同一把鎖,不能用匿名對(duì)象

????????????????????System.out.print("黑");

????????????????????System.out.print("馬");

????????????????????System.out.print("程");

????????????????????System.out.print("序");

????????????????????System.out.print("員");

????????????????????System.out.print("\r\n");

????????????????}

????????????}

????????????/*

?????????????* 非靜態(tài)同步函數(shù)的鎖是:this

?????????????* 靜態(tài)的同步函數(shù)的鎖是:字節(jié)碼對(duì)象

?????????????*/

????????????public static synchronized void print2() {?

????????????????System.out.print("傳");

????????????????System.out.print("智");

????????????????System.out.print("播");

????????????????System.out.print("客");

????????????????System.out.print("\r\n");

????????????}

????????}


###24.18_多線程(線程安全問題)(掌握)

* 多線程并發(fā)操作同一數(shù)據(jù)時(shí), 就有可能出現(xiàn)線程安全問題

* 使用同步技術(shù)可以解決這種問題, 把操作數(shù)據(jù)的代碼進(jìn)行同步, 不要多個(gè)線程一起操作


????????????public class Demo2_Synchronized {


????????????????/**

?????????????????* @param args

?????????????????* 需求:鐵路售票,一共100張,通過四個(gè)窗口賣完.

?????????????????*/

????????????????public static void main(String[] args) {

????????????????????TicketsSeller t1 = new TicketsSeller();

????????????????????TicketsSeller t2 = new TicketsSeller();

????????????????????TicketsSeller t3 = new TicketsSeller();

????????????????????TicketsSeller t4 = new TicketsSeller();


????????????????????t1.setName("窗口1");

????????????????????t2.setName("窗口2");

????????????????????t3.setName("窗口3");

????????????????????t4.setName("窗口4");

????????????????????t1.start();

????????????????????t2.start();

????????????????????t3.start();

????????????????????t4.start();

????????????????}


????????????}


????????????class TicketsSeller extends Thread {

????????????????private static int tickets = 100;

????????????????static Object obj = new Object();

????????????????public TicketsSeller() {

????????????????????super();


????????????????}

????????????????public TicketsSeller(String name) {

????????????????????super(name);

????????????????}

????????????????public void run() {

????????????????????while(true) {

????????????????????????synchronized(obj) {

????????????????????????????if(tickets <= 0)

????????????????????????????????break;

????????????????????????????try {

????????????????????????????????Thread.sleep(10);//線程1睡,線程2睡,線程3睡,線程4睡

????????????????????????????} catch (InterruptedException e) {


????????????????????????????????e.printStackTrace();

????????????????????????????}

????????????????????????????System.out.println(getName() + "...這是第" + tickets-- + "號(hào)票");

????????????????????????}

????????????????????}

????????????????}

????????????}


###24.19_多線程(火車站賣票的例子用實(shí)現(xiàn)Runnable接口)(掌握)



###24.20_多線程(死鎖)(了解)

* 多線程同步的時(shí)候, 如果同步代碼嵌套, 使用相同鎖, 就有可能出現(xiàn)死鎖

????* 盡量不要嵌套使用


????????????private static String s1 = "筷子左";

????????????private static String s2 = "筷子右";

????????????public static void main(String[] args) {

????????????????new Thread() {

????????????????????public void run() {

????????????????????????while(true) {

????????????????????????????synchronized(s1) {

????????????????????????????????System.out.println(getName() + "...拿到" + s1 + "等待" + s2);

????????????????????????????????synchronized(s2) {

????????????????????????????????????System.out.println(getName() + "...拿到" + s2 + "開吃");

????????????????????????????????}

????????????????????????????}

????????????????????????}

????????????????????}

????????????????}.start();


????????????????new Thread() {

????????????????????public void run() {

????????????????????????while(true) {

????????????????????????????synchronized(s2) {

????????????????????????????????System.out.println(getName() + "...拿到" + s2 + "等待" + s1);

????????????????????????????????synchronized(s1) {

????????????????????????????????????System.out.println(getName() + "...拿到" + s1 + "開吃");

????????????????????????????????}

????????????????????????????}

????????????????????????}

????????????????????}

????????????????}.start();

????????????}


###24.21_多線程(以前的線程安全的類回顧)(掌握)

* A:回顧以前說過的線程安全問題

????* 看源碼:Vector,StringBuffer,Hashtable,Collections.synchroinzed(xxx)

????* Vector是線程安全的,ArrayList是線程不安全的

????* StringBuffer是線程安全的,StringBuilder是線程不安全的

????* Hashtable是線程安全的,HashMap是線程不安全的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • JUC 原創(chuàng)者:文思,感謝尚硅谷,資料來源于尚硅谷 目錄: 1、volatile關(guān)鍵字與內(nèi)存可見性 2、原子變量與...
    文思li閱讀 2,520評(píng)論 0 1
  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽閱讀 2,594評(píng)論 1 15
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,107評(píng)論 1 18
  • 7月20日知識(shí)點(diǎn) 今天的主要內(nèi)容——線程 線程線程的基本概念線程與進(jìn)程的區(qū)別線程的兩種創(chuàng)建方式(掌握)注意線程兩種...
    須臾之北閱讀 14,108評(píng)論 0 4
  • 關(guān)于選擇繼承Thread還是實(shí)現(xiàn)Runnable接口? 其實(shí)Thread也是實(shí)現(xiàn)Runnable接口的: 復(fù)制代碼...
    簡(jiǎn)單應(yīng)用閱讀 538評(píng)論 1 1

友情鏈接更多精彩內(nèi)容