2019-06-03 Java学习日记 day24 多线程
多線程
線程是程序執(zhí)行的一臺路徑,一個進程中可以包含多條線程
多線程并發(fā)執(zhí)行可以提高程序的效率,可以同時完成多項工作
多線程的應(yīng)用背景
紅蜘蛛同時共享屏幕給多個電腦
迅雷開啟多條線程一起下載
QQ同時和多個人一起視頻
服務(wù)器同時處理多個客戶端請求
?
多線程并行和并發(fā)
并行就是兩個任務(wù)同時運行,就是甲任務(wù)進行的同時,乙任務(wù)也在進行(需要多核CPU)
并發(fā)是指兩個任務(wù)都請求運行,而處理器只能接受一個任務(wù),就把這兩個任務(wù)輪流進行,由于時間間隔較短,使人感覺兩個任務(wù)都在運行
比如我跟兩個網(wǎng)友聊天,左手操作一個電腦跟甲聊,同時右手用另一臺電腦跟乙聊天,這就叫并行
如果用一臺電腦我先給甲發(fā)個信息,然后立刻再給乙發(fā)信息,然后再跟甲聊,再跟乙聊。這就叫并發(fā)
?
java程序運行原理和jvm的啟動
*java命令啟動java虛擬機,啟動jvm,等于啟動了一個應(yīng)用程序,也就是啟動了一個進程,該進程會自動啟動一個 “ 主線程 ”,然后主線程去調(diào)用某個類的 main 方法
?
*jvm啟動至少啟動了垃圾回收線程和主線程,所以是多線程的
?
多線程程序?qū)崿F(xiàn)
1. 繼承Thread
定義類繼承Thread
重寫run方法
把新線程要做的是寫在run方法中
創(chuàng)建線程對象
開啟新線程,內(nèi)部會自動執(zhí)行run方法
public class demo1_thread {public static void main(String[] args) {mythread mt1 =new mythread(); //創(chuàng)建thread類的子類對象mt1.start(); //開啟線程for(int i=0;i<1000;i++){System.out.println("bbbbb");}}} class mythread extends Thread{ //繼承threadpublic void run(){ //重寫run方法for(int i=0;i<1000;i++){System.out.println("aaaaaaaaaa");}} } 案例?
2. 實現(xiàn)runnable
定義類顯示Runnable接口
實現(xiàn)run方法
把新線程要做的事寫在run方法中
創(chuàng)建自定義的Runnable的子類對象
創(chuàng)建Thread對象,傳入Runnable
調(diào)用start()開啟新線程,內(nèi)部會自動調(diào)用Runnable的run方法
public class demo2_Runnnbale {public static void main (String args []){myrunnbale mr =new myrunnbale(); //創(chuàng)建runnable的子類對象new Thread(mr).start(); //將其當做參數(shù)傳遞給thread的構(gòu)造函數(shù),并開啟線程for (int i = 0; i < 1000; i++) {System.out.println("cc");}} } class myrunnbale implements Runnable{@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println("aaaaaaaaaaaaaa");}}} 案例實現(xiàn)Runnable的原理
看Thread類的構(gòu)造函數(shù),傳遞了Runnable接口的引用
通過init()方法找到傳遞的target給成員變量的target賦值
查看run方法,發(fā)現(xiàn)run方法中有判斷,如果target不為null就會太哦用Runnable接口子類對象的run方法
?
兩種方式的區(qū)別
1.繼承Thread:由于子類重寫了Thread類的run(),方太哦用start()時,直接找子類的run()方法
2.實現(xiàn)Runnable:構(gòu)造函數(shù)中傳入了Runnable的引用,成員變量記住了它,start()調(diào)用run()方法時內(nèi)部成員變量Runnable引用是否為空,不為空編譯時看的siRunnable的run(),運行時執(zhí)行的獅子類的run()方法
?
繼承Thread:
好處是:可以直接使用Thread類中的方法,代碼簡單
弊端是:如果已經(jīng)有父類,就不能用這種方法
實現(xiàn)Runnable接口:
好處是:即使自己定義的縣城類有了父類也沒關(guān)系,因為有了父類也可以實現(xiàn)接口,而且接口是可以多實現(xiàn)的
弊端是:不能直接使用Thread中的方法需要先獲取到線程對象后,才能得到Thread的方法,代碼復(fù)雜
?
匿名內(nèi)部類實現(xiàn)線程
1.繼承Thread方法
2.實現(xiàn)Runnable方法
public class demo3_Thread {public static void main(String[] args) {new Thread(){ //繼承Thread方法public void run(){ //重寫run方法for (int i = 0; i < 3000; i++) {System.out.println("aaaaaaaaa");}}}.start(); //開啟線程new Thread(new Runnable(){public void run(){for (int i = 0; i < 3000; i++) {System.out.println("bbb");}}}).start();}} 案例?
獲取名字
1.通過geyName()方法獲取線程對象的名字
設(shè)置名字
2.通過構(gòu)造方法函數(shù)可以傳入String類型的名字
?
通過setName(String)方法可以設(shè)置線程對象的名字
public class demo1_Name {public static void main (String args[]){new Thread("大哥"){public void run(){System.out.println(this.getName()+"aaaaaaaa");}}.start();new Thread(){public void run(){this.setName("戰(zhàn)三");System.out.println(this.getName()+"bb");}}.start();Thread t1= new Thread("大哥"){public void run(){System.out.println(this.getName()+"aaaaaaaa");}};t1.setName("李");t1.start();} } 案例?
獲取當前線程的對象
Thread.currentThread(),主線程也可以獲取
public class demo2_currentthread {public static void main(String[] args) {new Thread("毛毛"){public void run (){System.out.println(getName()+"...aaaaaaa");}}.start();new Thread(new Runnable(){public void run(){//Thread.currentThread()獲取當前正在執(zhí)行的線程System.out.println(Thread.currentThread().getName()+"...bb");}}).start();Thread.currentThread().setName("主線程");System.out.println(Thread.currentThread().getName());}} 案例?
休眠線程
Thread.sleep(毫秒,納秒),控制當前線程休眠若干毫秒1秒 =1000 * 1000 * 1000納秒? 1000000000
public class demo3_seelp {public static void main(String[] args) throws InterruptedException {//demo1();new Thread(){public void run(){for (int i = 20; i >=0; i--) {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}System.out.println(getName()+"...a");}}}.start();new Thread(){public void run(){for (int i = 20; i >=0; i--) {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}System.out.println(getName()+"..bb");}}}.start();}public static void demo1() throws InterruptedException {for(int i=20;i>=0;i--){Thread.sleep(1000);System.out.println("倒計時"+i+"秒");}}} 案例?
守護線程
setDaemon(),設(shè)置一個線程為守護線程,該線程不會單獨執(zhí)行,當其他飛守護線程都執(zhí)行結(jié)束后,自動退出
public class demo4_daemon {public static void main(String[] args) {Thread t1 =new Thread(){public void run(){for (int i = 0; i < 2; i++) {System.out.println(getName()+"..aaaaaaaa");}}};Thread t2 =new Thread(){public void run(){for (int i = 0; i < 50; i++) {System.out.println(getName()+"..bb");}}};t2.setDaemon(true); //當傳入true就是意味著設(shè)置為守護線程 t1.start();t2.start();}} 案例?
加入線程
join(),當前線程暫停,等待指定的線程執(zhí)行結(jié)束后,當前線程在繼續(xù)
join(int),可以等待指定的毫秒之后繼續(xù)
public class demo5_Join {public static void main(String[] args) {final Thread t1 =new Thread(){public void run (){for(int i=0; i<10 ;i++){System.out.println(getName()+"...aaaaaaaaa");}}};Thread t2 =new Thread(){public void run (){for(int i=0; i<10 ;i++){if(i==2){try {t1.join(1);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(getName()+"...bb");}}};t1.start();t2.start();}} 案例?
禮讓線程
yield讓出cpu
?
設(shè)置線程的優(yōu)先級
setPriority() 設(shè)置線程的優(yōu)先級
N1.setPriority(Thread.MIN_PRIORITY);? ? ? ? ? ? //設(shè)置最大的線程優(yōu)先級
N2.setPriority(Thread.MAX_PRIORITY);? ? ? ? ? ?//設(shè)置最小線程優(yōu)先級
?
同步代碼塊
什么情況下需要同步
當多線程并發(fā),有多段代碼同時執(zhí)行是,我們希望某一段代碼執(zhí)行的過程中cpu不要切換到其他線程工作,這是就需要同步
如果兩端代碼是同步的,那么同一時間值執(zhí)行一段,在一段代碼每執(zhí)行結(jié)束之前,不會執(zhí)行另一端代碼
同步代碼塊
使用synchronized關(guān)鍵字加上一個鎖對象來定義一段代碼,這就叫同步代碼塊
多個同步代碼塊如果使用相同的鎖對象,那么他們就是同步的
public class test_sybchronized {public static void main(String[] args) {final pritner p1=new pritner();new Thread(){public void run(){while(true){p1.print1(); }}}.start();new Thread(){public void run(){while(true){p1.print2(); }}}.start();}} class pritner{ demo d=new demo();public void print1(){synchronized (d) {System.out.println("學習");}}public void print2(){System.out.println("學校");} }class demo{} 案例?
同步方法
*使用synchronized 關(guān)鍵字修飾一個方法,該方法中所有的代碼都是同步的
public class test2_sybchronized {public static void main(String[] args) {final pritner2 p1=new pritner2();new Thread(){public void run(){while(true){p1.print1(); }}}.start();new Thread(){public void run(){while(true){p1.print2(); }}}.start();}} class pritner2{//非靜態(tài)放入同步方法的鎖對象是this//靜態(tài)的鎖不方法的鎖對象是:該類的字節(jié)碼對象public synchronized void print1(){System.out.print("學");System.out.print("習");System.out.print("的");System.out.print("心");System.out.print("\r\n");}public void print2(){synchronized (this) { System.out.print("學");System.out.print("校");System.out.print("的");System.out.print("路");System.out.print("上");System.out.print("\r\n");}}} 案例?
線程安全問題
多線程并發(fā)操作同一數(shù)據(jù)時,就有可能出現(xiàn)線程安全問題
使用同步技術(shù)可以解決這種問題,把操作數(shù)據(jù)的代碼進行同步,不要多個線程一起操作
public class test2_ticket {public static void main(String[] args) {new ticket().start();new ticket().start();new ticket().start();new ticket().start();}} class ticket extends Thread{private static int ticket =100;public void run(){while(true){synchronized (ticket.class) { if(ticket <=0){break;}try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}System.out.println(getName() + "...這是第" + ticket-- + "號票");}}} } 案例?
死鎖
多線程同步的時候,如果同步代碼嵌套,使用相同鎖,就有可能出現(xiàn)死鎖
public class test3_ {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();}} 案例?
轉(zhuǎn)載于:https://www.cnblogs.com/JungTan0113/p/10970951.html
總結(jié)
以上是生活随笔為你收集整理的2019-06-03 Java学习日记 day24 多线程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转载】Sqlserver限制最大可使用
- 下一篇: java美元兑换,(Java实现) 美元