java線程一之創建線程、線程池以及多線程運行時間統計


線程和進程的基本概念

進程和線程是動態的概念。

        進程是 “執行中的程序“,是一個動詞,而程序是一個名詞,進程運行中程序的”代碼“,而且還有自己的計數器,寄存器,它會向系統申請系統資源。

        線程是進程中的一個控制流。一個程序可能可能包含多個任務並發運行,而線程就是指一個任務重頭到尾的執行流。

        說的在簡單點,線程是執行中的任務,一個程序包含多個任務。

 

多線程

       單處理器中,為提高處理器的使用率(最終目標),使得程序在進行IO輸入出等不需要處理器時,也能夠讓處理器在運轉,引進多線程處理機制。多線程可以使得程序運行的更快,執行效率更高,交互性更強,這是不言而喻的!

 

創建任務和線程

        一個任務是一個對象,所以為創建一個任務,必須定義一個類,定義一個任務類,為了說明這是一個任務類,它需要實現Runnable接口,這個接口只包含一個run方法。

當我們定義好任務類taskClass之后,就可以用它的構造方法創建一個任務啦:TaskClass  task = new TaskClass(.....);

        我們創建的任務只能在線程中運行,Thread類中包含了創建線程以及控制線程的眾多方法。使用下面的語句創建任務線程:Thread  thread  = new Thread(task);

        然后調用start()方法告訴java虛擬機該線程准備運行thread.start();之后java虛擬機通過調用任務的run()方法執行任務。

 

事例代碼:

public class TaskThreadDemo{
	public static void main(String[] args)
	{
		//創建任務   並且需要為任務 創建 任務類,使用該類的構造方法創建任務
		PrintChar printA = new PrintChar('a',100);
		PrintChar printB = new PrintChar('b',100);
		PrintNum print100 = new PrintNum(100);
		
		//為任務創建線程
		Thread thread1 = new Thread(printA);
		Thread thread2 = new Thread(printB);
		Thread thread3= new Thread(print100);
		
		//告訴虛擬機器線程開始運行
		thread1.start();
		thread2.start();
		thread3.start();
	}
}

class PrintChar implements Runnable
{
	private char  charToPrint;
	private int items;
	
	public PrintChar(char c,int t)
	{
		charToPrint = c;
		items = t;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<items;i++)
		{
			System.out.print(charToPrint);
		}
	}
}

class PrintNum implements Runnable
{
	private int lastNumb;
	public PrintNum(int n)
	{
		lastNumb = n;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i= 1;i<100;i++)
		{
			System.out.print(" "+lastNumb); 
		}
	}

}

 

6fdaf34c50434bf5bab9d149c7fccc4c

 

一個好玩的閃爍文本框,直接用線程,不用main方法

import javax.swing.JApplet;
import javax.swing.JLabel;
public class FlashingText extends JApplet implements Runnable {
	private static final long serialVersionUID = 1L;
	private JLabel jlbText = new JLabel("Welcome",JLabel.CENTER);
	
	public FlashingText()
	{
		add(jlbText);
		new Thread(this).start();
	}
	
	public void run()
	{
		try {
			while(true)
			{
				if(jlbText.getText()==null)
					jlbText.setText("Welcome");
				else 
					jlbText.setText(null);
				Thread.sleep(200);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}

 

ed611650e460458198ca7b12d26f387fa28aa6938f9645578293e2a7e193c531

 

Thread類

        Thread類實現了Runnable接口,它包含為任務而創建線程的構造方法,以及控制方法,下圖就是Thread類常見的控制線程的方法:

iirj8`ilw}dr

          因為Thread類實現了Runnable接口,所以可以定義一個Thread的擴展類,里面實現run方法,這樣也可以創建一個線程類,但並不是很推薦這種方法,因為它將創建任務和運行任務的機制混在了一起,將任務從線程中分離出來比較好,即盡量使用Runnable接口創建線程,這樣得到的線程更加靈活,避免了java單繼承帶來的局限性

 

線程池

           線程池是管理並發執行任個數的理想方法,java提供Executor接口來執行線程池中的任務,提供ExecutorService接口來管理和控制任務。為了創建Executor接口實例,我們可以用Executors類,Executors類提供了創建Executor接口對象的靜態方法,下圖描述了上面的上面所說的關系。

clipboard

 

       線程池中的shutdown()方法一般都是放在main方法的后面部分,當所以的線程都添加到線程池中,即便有線程沒有執行完畢,也可能會關閉線程池,未執行完的線程繼續執行,所以main方法可能比子線程先結束。

利用isTerminated()進行線程池中所有線程運行時間的統計

       倘若希望主線程在子線程全部做完之后在執行,可以考慮讓所以的子線程用jion方法,但這可能導致所有子線程變成串行,不是很好的辦法,當然我們也可以多線程的輔助類CountDownLatch,這是一個與計時器有點類似功能的類。這次在看書學習的時候,發現了一個更好的辦法,就是在shutdown()方法后加上一句while(!executor.isTerminated()){},這是一個不錯的方法(不過我把shoudown()方法放在該while語句后面,就會陷入死循環,應該是要先關閉線程池,在判斷線程池中的線程是否全部終止,因為也有可能在while語句后面在添加新的子線程)。

       isTerminated()方法:如果線程池中所以線程都已完成並終止,則返回true.

       可以使用CountDownLatch 和上面的方法對程序運行計時統計,不過我記得CountDownLatch類是需要指定線程的個數。

事例代碼

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorDemo {
	public static void main(String[] args){
		long start = System.currentTimeMillis();
		System.out.println("當前時間"+"  "+start);
		ExecutorService executor = Executors.newFixedThreadPool(4);
		
		executor.execute(new PrintChar('a',100));
		executor.execute(new PrintChar('b',100));
		executor.execute(new PrintChar('c',100));
	    executor.execute(new PrintNum(100));
	    
	    executor.shutdown();
		while(!executor.isTerminated()){
			//System.out.print("-");
		};
		
		long end = System.currentTimeMillis();
		System.out.println("\n當前時間"+"  "+end);
		System.out.println("\n用時"+"  "+(end-start)+"毫秒");
	}
}
 
運行截圖
3015774f9c88408286aa07f7c77a10db 截圖1      572ff3bc5ea7495d9f207f5971a731a9截圖2

         不過不知道運行太快的原因,還是啥別的原因, 會出現截圖2的情況,網上很少關於isTerminated()方法的介紹,如有大神知道原因,還請告知小弟。

 

         這篇博客是自己在學習《java語言程序設計進階篇》時所在筆記,代碼出自書上,最后那個記時的加了計時部分。大三開學在即,希望現在來學java還來得及。

本文出自於博客園蘭幽,轉載請說明出處。


免責聲明!

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



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