1. 程式人生 > >多執行緒_callable_執行緒的狀態_執行緒的停止_執行緒的阻塞(join,yield,sleep)_currentThread_priority_day30

多執行緒_callable_執行緒的狀態_執行緒的停止_執行緒的阻塞(join,yield,sleep)_currentThread_priority_day30

1.使用callable介面實現多執行緒


我們繼續用這個多執行緒來實現龜兔賽跑:

package callable;

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;

/**
 * 我們用callable來模擬一下龜兔賽跑
 * 
 * @author Wang
 *
 */

public class Demo {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService ser = Executors.newFixedThreadPool(2);//這裡就是建立兩個執行緒
		
		Race tortoise = new Race("烏龜",1000);//1s走一步
		Race rabbit = new Race("小兔子",500);//0.5s
		
		Future<Integer> result1 =ser.submit(tortoise) ;//獲取執行緒體返回過來的值   要用對應的型別進行接收
		Future<Integer> result2 =ser.submit(rabbit) ;
		
		Thread.sleep(2000); //2秒  讓執行緒執行兩秒
		tortoise.setFlag(false); //停止執行緒體迴圈
		rabbit.setFlag(false);
		
		int num1 =result1.get(); //注意這個地方要接收值
		int num2 =result2.get();
		System.out.println("烏龜跑了-->"+num1+"步");
		System.out.println("小兔子跑了-->"+num2+"步");
		//停止服務 
		ser.shutdownNow();//關閉執行緒
	}
}


class Race implements Callable <Integer> {//這裡的Integer的作用是返回的是Interger型別的

	private String name;  //建立的這個執行緒叫什麼名字
	private long time;    //多長時間走一步
	private boolean flag = true;//標誌位
	private int step;//走了多少步
	
	public Race() {
		
	}
	
	public Race(String name, long time) {
		super();
		this.name = name;
		this.time = time;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public long getTime() {
		return time;
	}

	public void setTime(long time) {
		this.time = time;
	}

	public boolean isFlag() {
		return flag;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	public int getStep() {
		return step;
	}

	public void setStep(int step) {
		this.step = step;
	}

	@Override
	public Integer call() throws Exception {
		
		while(flag) {
			Thread.sleep(time);//程式睡眠多長時間  就是相當於多長時間走了一步
			step++;
		}
		return step;
	} 
	
} 

2.執行緒的狀態:



2.執行緒的停止:


package Stop;
/**
 * 
 * 外部干涉來停止執行緒
 * 
 * @author Wang
 * 
 */

public class StopDemo01 {
	public static void main(String[] args) throws InterruptedException {
		run r = new run();//搞清楚誰是實體
		new Thread(r).start();//這裡使用的是匿名類
		for(int i=0;i<30;i++) {
			if(i==10) {		//外部根據條件來呼叫停止對方法;		
				r.stop();
			}
			System.out.println(i);
		}
		
	}
}


class run implements Runnable{

	private boolean flag = true;//定義執行緒體中使用的標識
	
	@Override
	public void run() {
		while(flag) {//執行緒體使用該標識
			System.out.println("執行緒ing.....");
		}
	}
	
	void stop() {//提供外部的方法來改變標識
		flag = false;
		yi
	}
}
注意:其實Thread類(代理)裡面也有執行緒停止的方法只不過這些方法,不推薦使用,主要是這些方法不安全;

3.執行緒的阻塞:

1.join():合併執行緒

package Stop;

/**
 * 
 * 執行緒的阻塞 Join
 * 
 * @author Wang
 *
 */

public class JoinDemo01 extends Thread {

	public static void main(String[] args) throws InterruptedException {
		JoinDemo01 j = new JoinDemo01();//新生
		Thread t = new Thread(j);
		t.start();//就緒
		//cpu執行排程
		
		for(int i=0;i<200;i++) {
			if(i==50) {
				t.join();//這裡會把兩個執行緒合為一個    會繼續執行t但是變為了單執行緒   他執行玩以後在執行main()函式  所以我們就說main函式被阻塞;
			}
			System.out.println("main執行" + i);
		}

	}

	public void run() {// 重寫run()方法 這個就是執行緒體
		for (int i = 0; i < 200; i++) {
			System.out.println("執行j" + i);
		}
	}
}

2.yield():暫停自己的執行緒    static

package Stop;
/**
 * 
 * 測試Yield
 * 
 * @author Wang
 *
 */

public class Yield extends Thread{
	public static void main(String[] args) {
		Yield y = new Yield();
		Thread t = new Thread(y);
		t.start();
		
		for(int i=0;i<50;i++) {
			if(i==10) {
				Thread.yield();//他是一個靜態方法  在哪個執行緒裡呼叫就會暫停那個執行緒  這個暫停只是暫停一瞬間
			}
			System.out.println("main" + i);
		}
	}
	
	public void run() {// 重寫run()方法 這個就是執行緒體
		for (int i = 0; i < 100; i++) {
			System.out.println("執行y" + i);
		}
	}
}
3.sleep();睡眠  static,不釋放鎖(常用的方法)

one:與時間相關(模擬倒計時)

two:模擬網路延時

package Stop;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 
 * 測試一下sleep的用法
 * 
 * @author Wang
 *
 */

public class sleep {
	public static void main(String[] args)  throws InterruptedException {//寫一個當前時間的倒計時
		Date endTime = new Date(System.currentTimeMillis()+10*1000);//得到倒計時的開始時間  當前時間10s後的時間 
		long end = endTime.getTime();
		
		while(true) {
			System.out.println(new SimpleDateFormat("mm:ss").format(endTime));//將這個時間格式化為字串型別  採用了匿名類  這裡給你所在的地區時間不太一致是牽涉到時區的問題
			Thread.sleep(1000);
			endTime = new Date(endTime.getTime() - 1000);
			
			if(end-10000 >= endTime.getTime()) {//倒計時10後跳出
				break;
			}
		}
		
	}
}

看一下網路延時給我們帶來的問題:

package Stop;

import Runnable.Web;

/**
 * 
 * 來看一下網路延時所帶來的問題
 * 
 * @author Wang
 *
 */

public class SleepDemo02 implements Runnable{
	private int ticketNum = 50;
	
	@Override
	public void run() {
		while(true) {
			if(ticketNum<0) {
				break;
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "搶到了" + ticketNum--);
		}
		
	}
	
	public static void main(String[] args) {
		SleepDemo02 web = new SleepDemo02();//建立實體物件
		
		Thread thr1 = new Thread(web,"路人甲");//建立四個代理    他們來實現多執行緒的搶票
		Thread thr2 = new Thread(web,"黃牛");
		Thread thr3 = new Thread(web,"程式設計師");
		Thread thr4 = new Thread(web,"白領");
		
		
		thr1.start();
		thr2.start();
		thr3.start();
		thr4.start();
		
		
	}
}


從這張圖上我們可以看到搶票搶到-1的情況

看這裡當最後一次搶票的時候,這時候票還剩兩張,我們第一個代理和第二個代理都會進去while()   但是他們會休眠所以num還是大於0的  不跳出迴圈  這樣我們的另外兩個代理都會進入程式中,就會拿到0和-1;

4.測試currentThread()

package priority;
/**
 * 
 * 自己寫一個執行緒的實體
 * 
 * @author Wang
 *
 */

public class MyThread implements Runnable{

	private int num = 0;
	private boolean flag = true;
	
	@Override
	public void run() {
		while(flag) {
			System.out.println(Thread.currentThread().getName() + num++);//得到當前執行緒的名字;
		}
		
	}
	
	public void stop() {
		flag = false;
	}

}
package priority;
/**
 * 
 * 我們來測試一下這個類
 * 
 * @author Wang
 * 
 * Thread.currentThread()	 :當前執行緒
 * setName():設定名稱
 * getName():獲取名稱
 * isAlive():判斷狀態
 *
 */

public class currentThread {
	
	public static void main(String[] args) throws InterruptedException {
		MyThread mt = new MyThread();//建立一個是實體
		
		Thread proxy = new Thread(mt,"wang");
		proxy.setName("wanga");//更改執行緒的名字
		System.out.println(proxy.getName());
		System.out.println(Thread.currentThread().getName());//獲取當前執行緒的名字   在這裡應該是Main
		
		proxy.start();
		
		System.out.println(proxy.isAlive());
		
		Thread.sleep(5);
	
		mt.stop();
		Thread.sleep(5);//  這裡需要延時一下  給執行緒一個關閉的時間;
		
		System.out.println(proxy.isAlive());
		
		
	}

}

5.測試priority()

package priority;
/**
 * 
 * 我們來了解一下執行緒優先順序的問題
 * 優先順序:概率,不是絕對的先後順序
 * MAX_PRIORITY  10
 * NORM_PRIORITY 5 (預設的優先順序是這個)  
 * MIN_PRIORITY  1
 *  
 *  setPriority()
 *  getPriority()
 *  
 * @author Wang
 *
 */

public class PriorityDemo01 {
	public static void main(String[] args) throws InterruptedException {
		MyThread mt =new MyThread();
		Thread p1 =new Thread(mt,"aione");
		
		MyThread mt2 =new MyThread();
		Thread p2 =new Thread(mt2,"aitwo");
		
		p1.setPriority(Thread.MIN_PRIORITY); //設定優先順序
		p2.setPriority(Thread.MAX_PRIORITY);//設定優先順序    他的優先順序高   那麼他執行的概率就比較大
		p1.start();
		p2.start();
		
		
		
		Thread.sleep(1);
		mt.stop();
		mt2.stop();
	}
}

注意:我們學習java的基本知識就是學類和介面的;

         執行緒的優先順序高  就是執行他的概率大一點   而不是先執行優先順序高的  在執行優先順序低的;