国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

java必學必會之線程(1)

2019-11-26 14:47:44
字體:
來源:轉載
供稿:網友

一、線程的基本概念

  

線程理解:線程是一個程序里面不同的執行路徑

  每一個分支都叫做一個線程,main()叫做主分支,也叫主線程。

  程只是一個靜態的概念,機器上的一個.class文件,機器上的一個.exe文件,這個叫做一個進程。程序的執行過程都是這樣的:首先把程序的代碼放到內存的代碼區里面,代碼放到代碼區后并沒有馬上開始執行,但這時候說明了一個進程準備開始,進程已經產生了,但還沒有開始執行,這就是進程,所以進程其實是一個靜態的概念,它本身就不能動。平常所說的進程的執行指的是進程里面主線程開始執行了,也就是main()方法開始執行了。進程是一個靜態的概念,在我們機器里面實際上運行的都是線程。

  Windows操作系統是支持多線程的,它可以同時執行很多個線程,也支持多進程,因此Windows操作系統是支持多線程多進程的操作系統。Linux和Uinux也是支持多線程和多進程的操作系統。DOS就不是支持多線程和多進程了,它只支持單進程,在同一個時間點只能有一個進程在執行,這就叫單線程。

  CPU難道真的很神通廣大,能夠同時執行那么多程序嗎?不是的,CPU的執行是這樣的:CPU的速度很快,一秒鐘可以算好幾億次,因此CPU把自己的時間分成一個個小時間片,我這個時間片執行你一會,下一個時間片執行他一會,再下一個時間片又執行其他人一會,雖然有幾十個線程,但一樣可以在很短的時間內把他們通通都執行一遍,但對我們人來說,CPU的執行速度太快了,因此看起來就像是在同時執行一樣,但實際上在一個時間點上,CPU只有一個線程在運行。

學習線程首先要理清楚三個概念

1、進程:進程是一個靜態的概念
2、線程:一個進程里面有一個主線程叫main()方法,是一個程序里面的,一個進程里面不同的執行路徑。
3、在同一個時間點上,一個CPU只能支持一個線程在執行。因為CPU運行的速度很快,因此我們看起來的感覺就像是多線程一樣。
  什么才是真正的多線程?如果你的機器是雙CPU,或者是雙核,這確確實實是多線程。

二、線程的創建和啟動

  

  在JAVA里面,JAVA的線程是通過java.lang.Thread類來實現的,每一個Thread對象代表一個新的線程。創建一個新線程出來有兩種方法:第一個是從Thread類繼承,另一個是實現接口runnable。VM啟動時會有一個由主方法(public static void main())所定義的線程,這個線程叫主線程。可以通過創建Thread的實例來創建新的線程。你只要new一個Thread對象,一個新的線程也就出現了。每個線程都是通過某個特定的Thread對象所對應的方法run()來完成其操作的,方法run()稱為線程體。

范例1:使用實現Runnable接口創建和啟動新線程

開辟一個新的線程來調用run方法

package cn.galc.test;public class TestThread1{ public static void main(String args[]){ Runner1 r1 = new Runner1();//這里new了一個線程類的對象出來 //r1.run();//這個稱為方法調用,方法調用的執行是等run()方法執行完之后才會繼續執行main()方法 Thread t = new Thread(r1);//要啟動一個新的線程就必須new一個Thread對象出來 //這里使用的是Thread(Runnable target) 這構造方法 t.start();//啟動新開辟的線程,新線程執行的是run()方法,新線程與主線程會一起并行執行 for(int i=0;i<10;i++){  System.out.println("maintheod:"+i); } }}/*定義一個類用來實現Runnable接口,實現Runnable接口就表示這個類是一個線程類*/class Runner1 implements Runnable{ public void run(){ for(int i=0;i<10;i++){  System.out.println("Runner1:"+i); } }}

多線程程序執行的過程如下所示:

 

不開辟新線程直接調用run方法

 

運行結果如下:

 范例2:繼承Thread類,并重寫其run()方法創建和啟動新的線程

package cn.galc.test;/*線程創建與啟動的第二種方法:定義Thread的子類并實現run()方法*/public class TestThread2{ public static void main(String args[]){ Runner2 r2 = new Runner2(); r2.start();//調用start()方法啟動新開辟的線程 for(int i=0;i<=10;i++){  System.out.println("mainMethod:"+i); } }}/*Runner2類從Thread類繼承通過實例化Runner2類的一個對象就可以開辟一個新的線程調用從Thread類繼承來的start()方法就可以啟動新開辟的線程*/class Runner2 extends Thread{ public void run(){//重寫run()方法的實現 for(int i=0;i<=10;i++){  System.out.println("Runner2:"+i); } }}

  使用實現Runnable接口和繼承Thread類這兩種開辟新線程的方法的選擇應該優先選擇實現Runnable接口這種方式去開辟一個新的線程。因為接口的實現可以實現多個,而類的繼承只能是單繼承。因此在開辟新線程時能夠使用Runnable接口就盡量不要使用從Thread類繼承的方式來開辟新的線程。

三、線程狀態轉換

  

3.1.線程控制的基本方法

  

3.2. sleep/join/yield方法介紹

  

sleep方法的應用范例:

package cn.galc.test;import java.util.*;public class TestThread3 { public static void main(String args[]){ MyThread thread = new MyThread(); thread.start();//調用start()方法啟動新開辟的線程 try {  /*Thread.sleep(10000);  sleep()方法是在Thread類里面聲明的一個靜態方法,因此可以使用Thread.sleep()的格式進行調用  */  /*MyThread.sleep(10000);  MyThread類繼承了Thread類,自然也繼承了sleep()方法,所以也可以使用MyThread.sleep()的格式進行調用  */  /*靜態方法的調用可以直接使用“類名.靜態方法名”  或者“對象的引用.靜態方法名”的方式來調用*/  MyThread.sleep(10000);  System.out.println("主線程睡眠了10秒種后再次啟動了");  //在main()方法里面調用另外一個類的靜態方法時,需要使用“靜態方法所在的類.靜態方法名”這種方式來調用  /*  所以這里是讓主線程睡眠10秒種  在哪個線程里面調用了sleep()方法就讓哪個線程睡眠,所以現在是主線程睡眠了。  */ } catch (InterruptedException e) {  e.printStackTrace(); } //thread.interrupt();//使用interrupt()方法去結束掉一個線程的執行并不是一個很好的做法 thread.flag=false;//改變循環條件,結束死循環 /**  * 當發生InterruptedException時,直接把循環的條件設置為false即可退出死循環,  * 繼而結束掉子線程的執行,這是一種比較好的結束子線程的做法  */ /**  * 調用interrupt()方法把正在運行的線程打斷 相當于是主線程一盆涼水潑上去把正在執行分線程打斷了 分線程被打斷之后就會拋InterruptedException異常,這樣就會執行return語句返回,結束掉線程的執行 所以這里的分線程在執行完10秒鐘之后就結束掉了線程的執行  */ }}class MyThread extends Thread { boolean flag = true;// 定義一個標記,用來控制循環的條件 public void run() { /*  * 注意:這里不能在run()方法的后面直接寫throw Exception來拋異常,   * 因為現在是要重寫從Thread類繼承而來的run()方法,重寫方法不能拋出比被重寫的方法的不同的異常。  * 所以這里只能寫try……catch()來捕獲異常  */ while (flag) {  System.out.println("==========" + new Date().toLocaleString() + "===========");  try {  /*   * 靜態方法的調用格式一般為“類名.方法名”的格式去調用 在本類中聲明的靜態方法時調用時直接寫靜態方法名即可。 當然使用“類名.方法名”的格式去調用也是沒有錯的   */  // MyThread.sleep(1000);//使用“類名.方法名”的格式去調用屬于本類的靜態方法  sleep(1000);//睡眠的時如果被打斷就會拋出InterruptedException異常  // 這里是讓這個新開辟的線程每隔一秒睡眠一次,然后睡眠一秒鐘后再次啟動該線程  // 這里在一個死循環里面每隔一秒啟動一次線程,每個一秒打印出當前的系統時間  } catch (InterruptedException e) {  /*   * 睡眠的時一盤冷水潑過來就有可能會打斷睡眠    * 因此讓正在運行線程被一些意外的原因中斷的時候有可能會拋被打擾中斷(InterruptedException)的異常   */  return;  // 線程被中斷后就返回,相當于是結束線程  } } }}

運行結果:

 join方法的使用范例:

package cn.galc.test;public class TestThread4 { public static void main(String args[]) { MyThread2 thread2 = new MyThread2("mythread"); // 在創建一個新的線程對象的同時給這個線程對象命名為mythread thread2.start();// 啟動線程 try {  thread2.join();// 調用join()方法合并線程,將子線程mythread合并到主線程里面  // 合并線程后,程序的執行的過程就相當于是方法的調用的執行過程 } catch (InterruptedException e) {  e.printStackTrace(); } for (int i = 0; i <= 5; i++) {  System.out.println("I am main Thread"); } }}class MyThread2 extends Thread { MyThread2(String s) { super(s); /*  * 使用super關鍵字調用父類的構造方法   * 父類Thread的其中一個構造方法:“public Thread(String name)”   * 通過這樣的構造方法可以給新開辟的線程命名,便于管理線程  */ } public void run() { for (int i = 1; i <= 5; i++) {  System.out.println("I am a/t" + getName());  // 使用父類Thread里面定義的  //public final String getName(),Returns this thread's name.  try {  sleep(1000);// 讓子線程每執行一次就睡眠1秒鐘  } catch (InterruptedException e) {  return;  } } }}

運行結果:

yield方法的使用范例:

package cn.galc.test;public class TestThread5 { public static void main(String args[]) { MyThread3 t1 = new MyThread3("t1"); /* 同時開辟了兩條子線程t1和t2,t1和t2執行的都是run()方法 */ /* 這個程序的執行過程中總共有3個線程在并行執行,分別為子線程t1和t2以及主線程 */ MyThread3 t2 = new MyThread3("t2"); t1.start();// 啟動子線程t1 t2.start();// 啟動子線程t2 for (int i = 0; i <= 5; i++) {  System.out.println("I am main Thread"); } }}class MyThread3 extends Thread { MyThread3(String s) { super(s); } public void run() { for (int i = 1; i <= 5; i++) {  System.out.println(getName() + ":" + i);  if (i % 2 == 0) {  yield();// 當執行到i能被2整除時當前執行的線程就讓出來讓另一個在執行run()方法的線程來優先執行  /*   * 在程序的運行的過程中可以看到,   * 線程t1執行到(i%2==0)次時就會讓出線程讓t2線程來優先執行    * 而線程t2執行到(i%2==0)次時也會讓出線程給t1線程優先執行   */  } } }}

運行結果如下:

 以上就是本文的全部內容,對java線程進行全面學習,希望可以幫助到大家。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 辽宁省| 蒲江县| 盐山县| 钟祥市| 榕江县| 海城市| 和田县| 合水县| 霞浦县| 本溪市| 华安县| 汝州市| 金塔县| 密云县| 佳木斯市| 桑植县| 冷水江市| 阳春市| 咸丰县| 商河县| 兴隆县| 都昌县| 西乌| 九寨沟县| 五华县| 邵阳县| 贵州省| 仲巴县| 兴海县| 扎鲁特旗| 崇左市| 元江| 广南县| 万州区| 崇州市| 邮箱| 泰宁县| 石屏县| 凌云县| 英山县| 岑巩县|