java多線程學習筆記(一)

本文主要記錄了一些本人學習多線程的一下筆記,可作爲多線程入門參考。

一、線程簡介

介紹線程之前要介紹程序和進程:

程序:程序是一個指令和數據的有效集合,其本身沒有任何允許的含義,是一個靜態的概念;

進程:是執行程序的一次執行過程,他是一個動態的概念,是系統資源分配的單元;

線程:是cup調度和執行的單位。通常在一個進程中可以包含若干個線程,當然一個進程中至少有一個線程,不然沒有存在的意義;

多線程:一個進程中的多個線程。

注意:很多多線程是模擬出來的,真正的多線程是隻有多個cpu,即多核,如服務器。如果是模擬出來的多線程,即使在一個cpu的情況下,在同一時間點,cpu只能執行一個代碼,因爲切換很快,所以就有同時執行的錯覺。

二、多線程的創建方式

1、繼承Thread類

//創建線程方式一:繼承Thread類,重寫run()方法,調用start開啓線程
//總結:注意,線程開啓不一定立即執行,有cpu調度執行
public class TestThread1 extends Thread{

	@Override
	public void run() {
		//run方式線程實現體
		for (int i = 0; i < 200; i++) {
			System.out.println("我在看代碼---"+i);
		}
	}
	
	public static void main(String[] args){
		TestThread1 testThread1=new TestThread1();
		//testThread1.run(); //調用run方法,立即執行子線程
		testThread1.start();//調用start方法,開啓新的線程,但不一定立即執行,由cpu調度執行
		
		//main線程,主線程
		for (int i = 0; i < 200; i++) {
			System.out.println("我在學習多線程---"+i);
			
		}
	}
}

執行結果如下:

可以看出來兩個線程是交替執行的,每次執行結果都不一樣,是由cpu的調度執行的。

2、實現Runnable接口

//創建方式線程方式2:實現runnable接口,重寫run方法,執行線程需要丟入runnable接口實現類,調用start方法
public class TestThread2 implements Runnable{

	@Override
	public void run() {
		//run方式線程實現體
		for (int i = 0; i < 200; i++) {
			System.out.println("我在看代碼---"+i);
		}
	}
	
	public static void main(String[] args){
		//創建runnable接口的實現類對象
		TestThread2 testThread2=new TestThread2();
		//創建線程對象,通過線程對象來開啓我們的線程
		Thread thread=new Thread(testThread2);
		thread.start();//調用start方法,開啓新的線程,但不一定立即執行,由cpu調度執行
		
		//main線程,主線程
		for (int i = 0; i < 200; i++) {
			System.out.println("我在學習多線程---"+i);
			
		}
	}
}

運行結果如下:

使用龜兔賽跑的案例來鞏固一下實現Runnable接口:

/**
 * 模擬龜兔賽跑
 * 1、首先來個賽道距離,然後要距離終點越來越近
 * 2、判斷比賽是否結束
 * 3、打印出勝利者
 * 4、龜兔賽跑開始
 * 5、故事中烏龜是贏得,兔子需要睡覺,所以我們來模擬兔子睡覺
 * 6、烏龜贏得比賽
 *
 */
public class Race implements Runnable{
	//勝利者
	private static String winner;

	@Override
	public void run() {
		//定義跑道
		for (int i = 0; i <= 100; i++) {
			if(Thread.currentThread().getName().equals("兔子") && i%10==0){
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			//判斷比賽是否結束
			if(gamOver(i)){
				break;
			}
			System.out.println(Thread.currentThread().getName()+"-->"+"跑了"+i+"步");
		}
	}
	
	//判斷是否完成比賽
	public boolean gamOver(int steps){
		if(winner!=null){
			return true;
		}
		if(steps>=100){
			winner=Thread.currentThread().getName();
			//打印出勝利者
			System.out.println("winner is "+winner);
			return true;
		}
		return false;
	}

	public static void main(String[] args) {
		Race race=new Race();
		new Thread(race,"烏龜").start();
		new Thread(race,"兔子").start();
		
	}
}

運行結果如下:

3、實現Callable接口

import java.io.File;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.io.FileUtils;


/**
 * 創建線程方式三:實現callable接口
 * 好處:可以定義返回值
 * 		可以拋出異常
 *
 */
public class TestCallable  implements Callable<Boolean>{
	
	private String url;//圖片url
	private String name;//保存的文件名
	
	public TestCallable(String url,String name) {
		this.url=url;
		this.name=name;
	}

	@Override
	public Boolean call() throws Exception {
		WebDownloader webDownloader=new WebDownloader();
		webDownloader.downloader(url, name);
		System.out.println("下載了文件名爲:"+name);
		return true;
	}

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		TestCallable t1=new TestCallable("http://img.pconline.com.cn/images/upload/upc/tx/wallpaper/1209/26/c0/14139494_1348624365103.jpg","1.jpg");
		TestCallable t2=new TestCallable("https://www.2008php.com/09_Website_appreciate/10-07-26/12801466092ttaRB6xsN.jpg","2.jpg");
		TestCallable t3=new TestCallable("http://img.pconline.com.cn/images/upload/upc/tx/wallpaper/1308/17/c6/24564406_1376704633089.jpg","3.jpg");
		//創建服務
		ExecutorService ser=Executors.newFixedThreadPool(3);
		//提交執行
		Future<Boolean> r1=ser.submit(t1);
		Future<Boolean> r2=ser.submit(t2);
		Future<Boolean> r3=ser.submit(t3);
		//獲取結果
		boolean rs1=r1.get();
		boolean rs2=r2.get();
		boolean rs3=r3.get();
		System.out.println(rs1);
		System.out.println(rs2);
		System.out.println(rs3);
		//關閉服務
		ser.shutdown();
				
	}
}

class WebDownloader{
	//下載方法
	public void downloader(String url,String name){
		try {
			FileUtils.copyURLToFile(new URL(url),new File(name));
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("io異常,下載方法出現問題5");
		}
	}
}

4、小結

三種方法的區別:

繼承Thread類:

1. 子類繼承Thread類具備多線程能力;

2. 啓動線程:子類對象.start();

不建議使用:避免OOP單繼承侷限性

實現Runnable接口

1.實現Runnable具有多線程能力;

2.啓動線程:傳入目標對象+Thread對象.start()

推薦使用:避免單繼承侷限性,靈活方便,方便同一個對象被多個線程使用

實現Callable接口

1.實現Collable接口,需要返回值類型;

2.重寫call方法,需要拋出異常

3.創建目標對象

4.創建執行服務

5.提交執行:Future<Boolean> result1=ser.submit(t1);

6.獲取結果:boolean r1=result1.get();

7.關閉服務:server,shutdownNow();

二、線程狀態

請看:https://blog.csdn.net/qq_33157666/article/details/103949045

發佈了58 篇原創文章 · 獲贊 87 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章