java筆記五:多線程的使用


  以前學習基礎的時候學習了一段時間的多線程,上課的時候老師也講過一遍,那時候感覺學的似懂非懂。因為到現在很長一段時間沒有用到多線程的知識,所以現在基本上忘了差不多了。但是下個星期要面試了,所以今天特意又研究了一下多線程,免得被問到多線程問題時什么都不記得了那就麻煩了。現在對java比較熟悉了,所以再一次學習多線程知識,感覺沒有那么難了(記得剛接觸多線程的時候,感覺非常吃力)。

  首先講一下進程和線程的區別:

    進程:每個進程都有獨立的代碼和數據空間(進程上下文),進程間的切換會有較大的開銷,一個進程包含1--n個線程。

    線程:同一類線程共享代碼和數據空間,每個線程有獨立的運行棧和程序計數器(PC),線程切換開銷小。

    線程和進程一樣分為五個階段:創建、就緒、運行、阻塞、終止。

    多進程是指操作系統能同時運行多個任務(程序)。

    多線程是指在同一程序中有多個順序流在執行。

  在java中創建一個線程有兩種方法:

    ①實現java.lang.Runnable接口,重寫run()方法,啟動:new Thread(this).start()。

 1 package com.thread;
 2 
 3 public class ThreadTest1 {
 4     public static void main(String[] args) {
 5         Runnable1 r = new Runnable1();
 6         //r.run();並不是線程開啟,而是簡單的方法調用
 7         Thread t = new Thread(r);//創建線程
 8         //t.run(); //如果該線程是使用獨立的 Runnable 運行對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執行任何操作並返回。
 9         t.start(); //線程開啟
10         for (int i = 0; i < 100; i++) {
11             System.out.println("main:"+i);
12         }
13     }
14 }
15 class Runnable1 implements Runnable{
16     public void run() {
17         for (int i = 0; i < 100; i++) {
18             System.out.println("Thread-----:"+i);
19         }
20     }
21 }

  要注意的是:

    1.r.run()並不是啟動線程,而是簡單的方法調用。

    2.Thread也有run()方法,如果該線程是使用獨立的 Runnable 運行對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執行任何操作並返回。

    3.並不是一啟動線程(調用start()方法)就執行這個線程,而是進入就緒狀態,什么時候運行要看CUP。

    ②繼承java.lang.Thread類,重寫run()方法。

 1 package com.thread;
 2 
 3 public class TestThread2 {
 4     public static void main(String[] args) {
 5         Thread1 t = new Thread1();
 6         //t.run(); //這里也不能直接調用方法
 7         t.start();
 8         for (int i = 0; i < 100; i++) {
 9             System.out.println("main:"+i);
10         }
11     }
12 }
13 
14 //盡量使用實現Runnnable接口,因為接口比較靈活
15 class Thread1 extends Thread{
16     @Override
17     public void run() {
18         for (int i = 0; i < 100; i++) {
19             System.out.println("Thread-----:"+i);
20         }
21     }
22 }

雖然兩種方法都可行,但是最好還是用第一種方法,因為使用接口靈活性好,java中時單繼承、多實現。

Thread類中常用的方法有:

  ①sleep(long millis): 在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行)。

 1 package com.thread;
 2 import java.util.Date;
 3 /**
 4  * sleep()指在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行)。
 5  * @author Administrator
 6  *
 7  */
 8 public class SleepTest {
 9     public static void main(String[] args) {
10         Thread2 t = new Thread2();
11         t.start();
12         try {
13             Thread.sleep(10000); //主線程睡眠10秒鍾
14         } catch (InterruptedException e) {
15             e.printStackTrace();
16         }
17         //主線程睡眠10秒鍾后結束t線程
18         //t.interrupt(); //這種結束方式比較粗暴,如果t線程打開了某個資源還沒來得及關閉也就是run方法還沒有執行完就強制結束線程,會導致資源無法關閉
19         //t.stop();也是結束某個線程,這種方式比interrupt()更粗暴
20         t.flag = false;
21     }
22 }
23 class Thread2 extends Thread{
24     boolean flag = true; //用這種方式結束線程很不錯,用一個變量控制run方法什么時候不再執行,不會出現run方法沒有執行完畢就結束
25     @Override
26     public void run() { //run方法一結束,整個線程就終止了
27         while(flag){
28             System.out.println("---"+new Date()+"---");
29             try {
30                 sleep(1000);
31             } catch (InterruptedException e) {
32                 return;
33             }
34         }
35     }
36 }

 

  ②join():指等待t線程終止。也可以理解為將t線程合並到當前線程來,等待t線程結束后再往下執行。相當於方法調用

 1 package com.thread;
 2 
 3 import java.util.Date;
 4 
 5 /*
 6  * t.join()方法指等待t線程終止。也可以理解為將t線程合並到當前線程來,等待t線程結束后再往下執行。相當於方法調用
 7  */
 8 public class TestJoin {
 9     public static void main(String[] args) {
10         Thread t = new Thread3("abc");
11         t.start();
12         for (int i = 0; i < 20; i++) {
13             System.out.println("我是main線程");
14             if(i==10){
15                 try {
16                     t.join();
17                 } catch (InterruptedException e1) {
18                     // TODO Auto-generated catch block
19                     e1.printStackTrace();
20                 }
21             }
22             try {
23                 Thread.sleep(1000);
24             } catch (InterruptedException e) {
25                 e.printStackTrace();
26             }
27         }
28     }
29 }
30 class Thread3 extends Thread{
31     public Thread3(String s) { //給該線程取一個名字,用getName()方法可以去到該名字
32         super(s);
33     }
34     @Override
35     public void run() {
36         for (int i = 0; i < 20; i++) {
37             System.out.println("我是"+getName()+"線程");
38             try {
39                 sleep(1000);
40             } catch (InterruptedException e) {
41                 e.printStackTrace();
42             }
43         }
44     }
45 }

運行該程序結果為:

 1 我是main線程
 2 我是abc線程
 3 我是main線程
 4 我是abc線程
 5 我是main線程
 6 我是abc線程
 7 我是main線程
 8 我是abc線程
 9 我是main線程
10 我是abc線程
11 我是main線程
12 我是abc線程
13 我是main線程
14 我是abc線程
15 我是main線程
16 我是abc線程
17 我是main線程
18 我是abc線程
19 我是main線程
20 我是abc線程
21 我是main線程
22 我是abc線程
23 我是abc線程
24 我是abc線程
25 我是abc線程
26 我是abc線程
27 我是abc線程
28 我是abc線程
29 我是abc線程
30 我是abc線程
31 我是abc線程
32 我是main線程
33 我是main線程
34 我是main線程
35 我是main線程
36 我是main線程
37 我是main線程
38 我是main線程
39 我是main線程
40 我是main線程

可以看到從第22行起就開始順序執行了,因為i=10的時候就將該形成合並了。

  ③yield():暫停當前正在執行的線程對象,並執行其他線程。

  ④setPriority(): 更改線程的優先級。

    MIN_PRIORITY = 1
       NORM_PRIORITY = 5
           MAX_PRIORITY = 10

 1 package com.thread;
 2 
 3 
 4 /*t.yield()暫停當前正在執行的線程對象,並執行其他線程。
 5  * 
 6  * MIN_PRIORITY 1
 7  * NORM_PRIORITY 5
 8  * MAX_PRIORITY 10
 9  */
10 public class TestYield {
11     public static void main(String[] args) {
12         Thread4 t1 = new Thread4("t1");
13         Thread4 t2 = new Thread4("t2");
14         t1.setPriority(Thread.MAX_PRIORITY);
15         t2.setPriority(Thread.MIN_PRIORITY);
16         System.out.println(t1.getPriority());
17         System.out.println(t2.getPriority());
18         t1.start();
19         t2.start();
20         
21     }
22 }
23 class Thread4 extends Thread{
24     public Thread4(String s) { 
25         super(s);
26     }
27     @Override
28     public void run() {
29         for (int i = 0; i < 1000; i++) {
30             System.out.println("我是"+getName()+"線程"+i);
31             if(i%10 == 0){
32                 yield();
33             }
34         }
35     }
36 }

由於運行結果太長就沒有貼上來了,運行該程序,可以看到t1和t2兩個進程每次當i為10的倍數時都會讓給其他線程執行。

  ⑤interrupt():中斷某個線程,這種結束方式比較粗暴,如果t線程打開了某個資源還沒來得及關閉也就是run方法還沒有執行完就強制結束線程,會導致資源無法關閉

  要想結束進程最好的辦法就是用sleep()函數的例子程序里那樣,在線程類里面用以個boolean型變量來控制run()方法什么時候結束,run()方法一結束,該線程也就結束了。

  ⑥還有很多的方法就不一一列舉了.........

  

  當然,多線程難點不在這些,多線程的難點在於多線程之間的協調。關於多線程的協調待續........

  

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM