android基礎學習-java篇day9-step3-第五節:java執行緒

發條魚發表於2018-09-12
  • 目錄

  • -執行緒的概念
  • -建立執行緒的兩種方式
  • -執行緒的狀態和生命週期
  • -sleep()和join方法
  • -執行緒的優先順序
  • -同步
  • -執行緒間通訊

什麼是程式?

程式是一個執行的程式;

是指可執行程式並存放在計算機儲存器的一個指令序列,它是一個動態執行的過程。

什麼是執行緒?

執行緒是比程式還要小的執行單位,一個程式包含多個執行緒;

執行緒可以看做是一個子程式。

執行緒的建立 

  • 建立一個Thread類,或者一個Thread子類的物件
  1. 子類繼承Thread類
  2. 在子類中重寫run()方法
  3. 主方法main中呼叫start()方法啟動執行緒
  • 建立一個實現Runnable介面的類的物件
  1. 通過執行緒實現類建立物件

  2. 將實現類的物件建立Thread的物件2

  3. 將實現類的物件建立Thread的物件2

Thread類

Thread是一個執行緒類,位於java.lang包下

構造方法 說明
Thread() 建立一個執行緒物件
Tread(String name) 建立一個具有指定名稱的執行緒物件
Thread(Runnable target) 建立一個基於Runnable介面實現類的執行緒物件
Tread(Runnable target,String name) 建立一個基於Runnable介面實現,並且指定名稱的執行緒物件

Thread類的常用方法

方法 說明
public void run() 執行緒相關的程式碼寫在該方法中,一般需要重寫
public void start() 啟動執行緒的方法
public static void sleep(long m) 執行緒休眠m毫秒的方法
public void join() 優先執行呼叫join()方法的執行緒

Runnable介面

  • 只有一個run();方法
  • Runnable是java中實現執行緒的介面
  • 實現執行緒功能的類都必須實現該介面

1、執行緒的簡單建立-繼承Thread:

package com.demo.day9.thread;
/*
 * 通過基礎Thread類的方式建立執行緒類,重寫run()方法
 */
class MyThread extends Thread{
	public void run() {
		System.out.println(getName()+"該執行緒正在執行!");
	}
	
}

public class ThreadTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("主執行緒1");
		MyThread mt=new MyThread();//建立物件
		mt.start();//呼叫start()方法啟動執行緒,執行run方法
		//start();只能執行一次
		System.out.println("主執行緒2");
		

	}

}

執行緒使用CPU的使用權是隨機的:

package com.demo.day9.thread;

class MyThreadOne extends Thread {
	//構造方法,給執行緒取個名字
	public MyThreadOne(String name) {
		super(name);
	}
	public void run() {
		for(int i=1;i<10;i++) {
			System.out.println(getName()+"正在執行"+i+"次");
		}
	}
	
}
public class TreadOne {

	public static void main(String[] args) {
		//建立執行緒物件
		MyThreadOne mt1=new MyThreadOne("執行緒1");
		MyThreadOne mt2=new MyThreadOne("執行緒2");
		mt1.start();
		mt2.start();
		//執行緒獲取CPU的使用權是隨機的、執行結果隨機

	} 

}

輸出結果隨機。。

2、執行緒建立-實現Runnale介面建立執行緒

為什麼要實現Runnable介面?

  • java不支援多繼承
  • 不打算重寫Thread類的其他方法
  • java支援實現多介面

 簡單案例:

package com.demo.day9.thread;
/*
 * 通過實現Runnable介面建立執行緒
 */
//建立執行緒實現類 PrintRunnale
 class PrintRunnable implements Runnable{

	@Override
	public void run() {
		//輸出正在進行的執行緒
		int i=1;
		while(i<10)
			System.out.println(Thread.currentThread().getName()+"正在進行"+(i++)+"次");
		//Thread.currentThread().getName() 獲取當前正在進行執行緒的名字
		
	}
	 
 }
public class MyRunnable {

	public static void main(String[] args) {
		//通過執行緒實現類建立物件
		PrintRunnable pt =new PrintRunnable();
		//將實現類的物件建立Thread的物件2
		Thread th=new Thread(pt);
		th.start();
		//將實現類的物件建立Thread的物件2
		//兩個物件共用一個實現類物件
		Thread th2=new Thread(pt);
		th2.start();

	}

}

 執行緒的狀態和生命週期

執行緒的五個狀態

  • 新建(New)
  • 可執行(Runnable)(又叫就緒)
  • 正在執行狀態(Running)
  • 阻塞(Blocked)
  • 終止(Dead)

執行緒的生命週期

sleep方法的應用

  • Thread類的方法

public static void sleep(long millis)

  • 作用:在指定的毫秒數內讓正在執行的執行緒休眠,暫停執行
  • 引數為休眠的時間,單位是毫秒
package com.demo.day9.thread;
//通過實現Runnable介面建立執行緒
class MyThreadTwo implements Runnable{

	@Override
	public void run() {
		for(int i=1;i<15;i++) {
			System.out.println(Thread.currentThread().getName()+"正在進行"+i+"次");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//讓執行緒休眠1秒
		}
		
	}
	
}

public class ThreadTwo {

	public static void main(String[] args) {
		// 建立執行緒類物件
		MyThreadTwo mt=new MyThreadTwo();
		//通過執行緒類物件建立Thread類物件呼叫start方法
		Thread th=new Thread(mt);
		th.start();

}
}

join方法的使用(強制CPU控制權)

  • Thread類的方法

public final void join()

  • 作用:等待呼叫該方法的執行緒結束後,之後的執行緒才能執行

public final void join(long millis)

作用:等待該執行緒終止的最長時間為millis毫秒,無論該執行緒是否執行完,要釋放CPU控制權

 

執行緒的優先順序

  • java為執行緒類提供了10個優先順序
  • 優先順序可以用整數1-10表示,超過範圍會丟擲異常
  • 主執行緒預設優先順序為5
  • 優先順序常量
  • -MAX_PRIORITY:執行緒的最高優先順序10
  • -MIN_PROIRITY:執行緒的最低優先順序1
  • -NORM_PROIRITY:執行緒的預設優先順序
  • 優先順序相關的方法
方法 說明
public int getPriority() 獲取執行緒的優先順序的方法
public void setPriority() 設定執行緒的優先順序的方法

執行緒同步synchronized

多執行緒執行存在的問題

  • 各個執行緒是通過競爭CPU時間而獲得執行機會的

  • 各執行緒什麼時候得到CPU時間,佔用多久,是不可預測的
  • 一個正在執行著的執行緒在什麼地方被暫停是不確定的

銀行存取款案例:

Bank.java

package com.demo.day9.thread;

public class Bank {
	private int balance;//賬戶餘額
	private String account;//賬戶
	//帶參構造,為變數賦值
	public Bank(String account,int balance) {
		this.setAccount(account);
		this.setBalance(balance);
	}

	public int getBalance() {
		return balance;
	}

	public void setBalance(int balance) {
		this.balance = balance;
	}

	public String getAccount() {
		return account;
	}

	public void setAccount(String account) {
		this.account = account;
	}
	//重寫toString
	public String toString() {
		
		return "賬戶為:"+this.getAccount()+" "+"餘額為:"+this.getBalance();
		
	}
    //存錢的方法
	public void savaAccount(){
		synchronized (this){//同步,執行這個執行緒,不允許其他執行緒搶佔CPU
		int balance=getBalance();//獲取當前賬戶餘額
		try {
			Thread.sleep(1000);//讓執行緒休眠1秒
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		balance+=100;//存入100元
		setBalance(balance);//
		System.out.println("存款後賬戶餘額:"+balance);
		}
	}
	public void  drawAccouct() {
		int balance=getBalance();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		balance-=200;//取款200
		setBalance(balance);
		System.out.println("取款後賬戶餘額:"+balance);
	
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

SaveAccount.java

package com.demo.day9.thread;
/*
 * 存款
 */
//通過實現Runnable介面來建立執行緒
public class SaveAccount implements Runnable{
	Bank bank;//建立Bank物件

	public SaveAccount(Bank bank) {
		super();
		this.bank = bank;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		bank.savaAccount();
	}
	

}

DrawAccount.java

package com.demo.day9.thread;
/*
 * 取款
 */
public class DrawAccount implements Runnable {
	Bank bank;
	public DrawAccount(Bank bank) {
		super();
		this.bank = bank;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		bank.drawAccouct();
	}

}

Test.java

package com.demo.day9.thread;

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Bank bank=new Bank("1001",1000);//建立物件bank
		SaveAccount sa=new SaveAccount(bank);
		DrawAccount da=new DrawAccount(bank);
		//建立執行緒物件
		Thread save =new Thread(sa);
		Thread draw =new Thread(da);
		save.run();
		draw.run();
		try {
			draw.join();
			save.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(bank);

	}

}

輸出:

存款後賬戶餘額:1100
取款後賬戶餘額:900
賬戶為:1001 餘額為:900

銀行存取款問題

  • 為了保證在存款或取款的時候,不允許其他執行緒進行操作
  • 需要將Bank物件進行鎖定
  • 使用關鍵字synchronized實現

同步

synchronized關鍵字用在

成員方法

public synchronized void saveAccount(){}

靜態方法

public static synchronized void saveAccount(){}

語句塊

synchronize (obj){.....}

執行緒間通訊

  • wait()方法:中斷方法的執行,是執行緒等待
  • 如果不配合notify方法使用,可能使兩個執行緒都處於等待狀態,陷入死鎖
  • notify()方法:喚醒處於等待的某個執行緒,使其等待結束
  • notifyAll()方法:喚醒所有處於等待的執行緒,使他們結束等待

 案例要求:

  • 生產者每生產一個後,消費者消費一個;
  • 不能存在生產者生產一個,消費者消費兩個
  • 或者生產者生產兩個,消費者消費一個

Queue.java

package com.demo.day9.thread;

public class Queue {
private int n;
boolean flag=false;//設預設flag為false。預設先生產
public synchronized int getN() {
	if(!flag) {//執行等待
		try {
			wait();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	System.out.println("消費"+n);
	flag=false;//消費完畢,再flag重新賦值為false
	notifyAll();//與wait()搭配使用,喚醒所有執行緒
	return n;
}
public synchronized void setN(int n) {
	if(flag) {//如果容器裡有資料,flag為true,執行等待
		try {
			wait();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	System.out.println("生產"+n);
	this.n = n;
	flag=true;//生產完畢,重新另flag為true
	notifyAll();//喚醒所有的執行緒
}
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}
	

}

Producer.java

package com.demo.day9.thread;

public class Producer implements Runnable{
  Queue queue;
  Producer( Queue queue){
	  this.setQueue(queue);
  }
  
  
	public Queue getQueue() {
	return queue;
}

public void setQueue(Queue queue) {
	this.queue = queue;
}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		int i=0;
		while(true) {
			queue.setN(i++);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	

}

Consumer.java

package com.demo.day9.thread;

public class Consumer implements Runnable {
	Queue queue;

	public Consumer(Queue queue) {
		super();
		this.queue = queue;
	}


 
	@Override
	public void run() {
	while(true)
	{
		queue.getN();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	}
	

}

TestQ.java

package com.demo.day9.thread;

public class TestQ {

	public static void main(String[] args) {
		// 建立Queue物件
		Queue queue=new Queue();
		//建立物件
		Producer p1=new Producer(queue);
		Consumer c1=new Consumer(queue);
		//實現上面建立的物件
//		Thread p=new Thread(p1);
//		Thread c=new Thread(c1);
//		p.start();
//		c.start();
		new Thread(new Producer(queue)).start();
		new Thread(new Consumer(queue)).start();
		

	}

}

輸出結果:

生產0
消費0
生產1
消費1
生產2
消費2
生產3
消費3
生產4
消費4
生產5
消費5
生產6....

綜合案例:

生成天氣資料,然後顯示出來

Weather.java

package com.test;
/*
 * 這是一個天氣類Weather,用於溫度和溼度資料的存放和讀取
 */
public class Weather {
	private int temperature;//溫度
	private int humidity;//溼度
	boolean flag=true;
	//帶參構造
	Weather(){
		this.setHumidity(humidity);
		this.setTemperature(temperature);
	}
	//生成天氣資料的方法
	public synchronized void generateWeather(int temp,int hum) {
		if(!flag)//如果flag=false
		{
		try {
			wait();//如果為flag為假讓它等待
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		}
		this.setHumidity(hum);
		this.setTemperature(temp);
		System.out.println("生成天氣資料:"+"[溫度:"+this.getTemperature()+",溼度:"+this.getHumidity()+"]");
		notifyAll();//喚醒所有等待
		flag=false;//重新flag賦值為false
		}
	//顯示天氣資料的方法
	public  synchronized void readWeather() {
		if(flag) {//如果為真等待
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		System.out.println("讀取天氣資料:"+"[溫度:"+this.getTemperature()+",溼度:"+this.getHumidity()+"]");
		notifyAll();//喚醒所有等待
		flag=true;//重新flag賦值為false
	}

	public int getTemperature() {
		return temperature;
	}

	public void setTemperature(int temperature) {
		this.temperature = temperature;
	}

	public int getHumidity() {
		return humidity;
	}

	public void setHumidity(int humidity) {
		this.humidity = humidity;
	}
	

}

GenerateWeather.java

package com.test;
/*
 * 這個是個執行緒類,用於生成天氣資料,模擬生成100次
 */
public class GenerateWeather implements Runnable{
	Weather weather;
	
	GenerateWeather(Weather weather){
		this.weather=weather;
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	@Override
	public void run() {
		int i=1;
		int temp=32;
		int hum=26;
		while(i<100) {
			temp+=1;
			hum+=1;
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			weather.generateWeather(temp,hum);
			i++;
		}
	}
	

}

ReadWeather.java

package com.test;
/*
 * 這是一個執行緒類,用於讀取天氣資料
 */
public class ReadWeather implements Runnable {
	
	Weather weather;
	ReadWeather(Weather weather){
		this.weather=weather;	
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		int i=1;
		while(i<100) {
			weather.readWeather();
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			i++;
		}
	}
	

	
}

WeatherTest.java

package com.test;

public class WeatherTest {

	public static void main(String[] args) {
		Weather wt=new Weather();
		new Thread(new GenerateWeather(wt)).start();
		new Thread(new ReadWeather(wt)).start();


	}

}

顯示結果

生成天氣資料:[溫度:33,溼度:27]
讀取天氣資料:[溫度:33,溼度:27]
生成天氣資料:[溫度:34,溼度:28]
讀取天氣資料:[溫度:34,溼度:28]
生成天氣資料:[溫度:35,溼度:29]
讀取天氣資料:[溫度:35,溼度:29]
生成天氣資料:[溫度:36,溼度:30]
讀取天氣資料:[溫度:36,溼度:30]
生成天氣資料:[溫度:37,溼度:31]
讀取天氣資料:[溫度:37,溼度:31]
生成天氣資料:[溫度:38,溼度:32]
讀取天氣資料:[溫度:38,溼度:32]
.......

 

相關文章