歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Java多線程之多線程的基本使用

Java多線程之多線程的基本使用

日期:2017/3/1 9:14:02   编辑:Linux編程

  在總結JDBC數據庫連接池的時候,發現Java多線程這塊掌握得不是很好,因此回頭看了下多線程的內容。做一下多線程模塊的學習和總結,穩固一下多線程這塊的基礎。關於多線程的一些理論知識,這裡不想啰嗦太多,可以進行下搜索了解。

1. 如何使用Java創建多線程

  使用Java多線程,總的來說方法有兩種:①繼承Thread類,重寫run方法 ②把相關的類實現Runnable(可運行)接口,重寫run方法。③實現Callable接口(相對用得較少)

 1 package com.scl.thread;
 2 
 3 public class TestThread
 4 {
 5     public static void main(String[] args) throws Exception
 6     {
 7         String mainName = Thread.currentThread().getName();
 8         System.out.println(mainName + "線程開始運行");
 9 
10         // 方法1 使用繼承對線程進行調用
11         MyThread myThread = new MyThread();
12         myThread.setName("wft");
13         myThread.start();
14         myThread.join();
15 
16         // 方法2 繼承Runnable接口進行調用
17         Thread thread = new Thread(new MyRunnable());
18         thread.start();
19 
20         System.out.println(mainName + "線程結束");
21     }
23 }
24 
25 // 使用runnable開啟線程
26 class MyRunnable implements Runnable
27 {
28     @Override
29     public void run()
30     {
31         // 獲取調用線程的名字
32         String curName = Thread.currentThread().getName();
33         System.out.println(curName + "線程啟動");
34         try
35         {
36             Thread.sleep(1000);
37             System.out.println(curName + "正在運行");
38         }
39         catch (InterruptedException e)
40         {
41             e.printStackTrace();
42         }
43         System.out.println(curName + "線程結束");
44     }
45 }
46 
47 // 使用Thread進行run方法的編寫,開啟線程
48 class MyThread extends Thread
49 {
50     // Thread.currentThread()調用這個方法的線程名稱。
51     String s = Thread.currentThread().getName(); // 調用這個類的是main方法調用,run方法交由新線程操作
52 
53     public MyThread()
54     {
55         System.out.println("Thread.currentThread().getname()=" + Thread.currentThread().getName());
56         // 線程沒運行前初始化的名字.因為類的初始化跟線程運行無關,這裡返回的是處世話的名字
57         System.out.println("This.getName=" + this.getName());
58     }
59 
60     @Override
61     public void run()
62     {
63         // run方法交由新線程操作,所以調用的名稱不是main
64         String strName = Thread.currentThread().getName();
65         System.out.println("this.getName " + this.getName());
66         // main
67         System.out.println("do u no s?" + s);
68 
69         System.out.println(strName + " 開始數數");
70         for (int i = 0; i < 100; i++)
71         {
72             System.out.println(strName + " " + i);
73         }
74         System.out.println(strName + " 數數完畢");
75     }
76 
77     // 返回設置的name
78     public String bName()
79     {
80         return this.getName();
81     }
82 } 

最應該注意的是給線程標注名稱的時候,應該多使用Thread.currentThread().getname() 來獲取線程名稱。使用this.getName方法很容易出錯。

主要該注意的有如下兩個:

① 獲取名稱不在run方法裡面,永遠返回名稱為main。因為在構造線程類的時候,主線程main會進行代碼的初始化。run方法由新創建起來的線程去調用,這樣run方法裡面的名稱才能被正確獲取到

② 在繼承類的構造函數內,如上面MyThread的構造函數內調用getName()方法。該方法是由JDK 源碼Thread類繼承而來。new一個Thread實例時,系統���調用Thread

下的方法,代碼如下

   //Thread 類構造函數
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }


   // 私有的init方法
    private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
        init(g, target, name, stackSize, null);
    }

  //init 方法. 更詳細內容見JDK源碼Thread類363行
  private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc) 

所以在構造器內的初始化的時候調用init方法給線程設置name字段。導致參數名稱修改且以"Thread-"開頭。初始化完畢後,如果用戶設置過相關的線程名稱,系統會把該字段進行修改,可以運用上述代碼中的bName()函數進行驗證。

  在使用Java多線程的時候,不要直接調用某個實例下的run方法,如果直接使用run方法。則直接調用,不會開辟新的線程進行功能操作。

繼承Thread和實現Runnable接口的區別:

  ① 繼承Thread能夠簡單地實現線程開辟,但由於Java只支持單繼承。繼承Thread方法實現線程會有比較多的局限性

② 實現Runnable接口能夠很好的將線程代碼和業務邏輯代碼分離,但代碼結構相對復雜。一般都會使用實現Runnable方法創建線程。

2. Java多線程下常用方法

① join( ) 多線程是有cpu分配執行時間片段,如果要控制線程操作流程,則需要使用到join方法。join方法會阻塞主線程,主線程會等待join方法的線程執行完畢再繼續執行後續的操作。同時join方法可以添加時間,讓主線程等待一段時間,如果時間過了。則不再等待繼續執行。如:thread.join( ),當主線程編譯到該代碼時,主線程會停止下來等待thread線程執行完畢後,主線程再繼續後續操作

② sleep( ) 不釋放鎖資源,讓調用的線程進行等待。如:thread.sleep( ) ,但代碼執行到這一句時,thread會停止下來等待,直到被喚醒或者等到到sleep到的時間點後再進行後續操作。

③ wait( )和notify( )、notifyAll( ) 。這三個方法主要處理線程同步數據時使用。數據同步,也就是幾條線程在同時修改一份共享數據。如火車站5名銷售員同時在售賣火車票,火車票是固定數量的前提下,如何實現這5名銷售員同時知道火車票庫存、同一路段火車票售賣、車票信息共享等。

wait方法使當前線程暫停執行並釋放對象鎖標志。notify和notifyall方法會喚醒幾個等待的線程,讓線程重新獲取鎖代碼以便後續進行。線程狀態圖表如下:

關於使用鎖以及線程狀態內容,將在下一篇文章中進行總結(http://www.linuxidc.com/Linux/2016-07/133403.htm),上述內容若有問題,煩請指出糾正。

Copyright © Linux教程網 All Rights Reserved