当前位置:网站首页>線程及線程池

線程及線程池

2022-07-06 15:10:00 手可摘鑫晨

1,線程概念

一個程序運行後至少有一個進程,一個進程中可以包含多個線程。

線程是進程中的一個執行單元,負責當前進程中程序的執行,一個進程中至少有一個線程。一個進程中是可以有多個線程的,這個應用程序也可以稱之為多線程程序。

2,線程調度

分時調度:所有線程輪流獲取CPU的使用權,平均分配每個線程占用的CPU的時間。

搶占式調度:優先級高的線程先使用CPU,如果線程優先級相同,

3,主線程

java使用java.lang.Thread類代錶線程,所有線程對象都必須是Thread類或其他子類的實例。每個線程的作用是完成一定的任務,實際上就是執行一段程序流即一段順序執行的代碼。Java使用線程執行體來代錶這段程序流。

4,實現線程的方式


public class xiancehng {
	public static void main(String[] args) {		
		Thread thread = new SubThread();
		thread.start();			
	}
}
//創建子線程
class SubThread extends Thread {
	@Override
    //重寫run方法
	public void run() {
		Thread t = Thread.currentThread();
		String name = t.getName();
		for (int i = 0; i < 10; i++) {
			System.out.println(name + i);
		}
	}
}
public class xiangcheng2 {
	public static void main(String[] args) {
		Runnable runnable = new Runnable() {
			@Override
			public void run() {
				System.out.println("hello word");
			}
		};
		new Thread(runnable).start();
	}
}

5,多線程原理

public class duoxiancheng1 {
	public static void main(String[] args) {
		System.out.println("這裏是main線程");
		Thread thread = new ZiThread("小强");
		thread.start();
		for (int i = 0; i < 10; i++) {
			System.out.println("旺財" + i);
		}
	}
}

class ZiThread extends Thread {
	public ZiThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		Thread t = Thread.currentThread();
		String name = t.getName();
		for (int i = 0; i < 10; i++) {
			System.out.println(name + i);
		}
	}
}

 

 6,Thread類

構造方法:

        public Thread();                                                 分配一個新的線程對象

        public Thread(String name);                              分配一個指定名字的新的線程對象

        public Thread(Runnable target);                        分配一個指定目標的新的線程對象

        public Thread(Runnable target,String name);    分配一個指定目標的新的線程對象並指定名字

成員方法:

        public String getName();                                     獲取當前線程名稱

        public void start();                                               調用線程執行run方法

        public void run();                                                 線程執行的任務在此處定義

        public static void sleep(long millis);                    當前正在執行的線程指定多少毫秒暫停

        public static Thread currentThread();                 返回對當前正在執行的線程對象的引用

7,Thread和Runnable的區別

Runnable的優勢:

        1,適合多個線程操作同一個任務對象。

        2,可以避免java中的單繼承的局限性。

        3,增加程序的健壯性,實現解耦操作,代碼可以被多個線程共享,代碼和線程獨立。

        4,線程池只能放入實現Runable或Callable類線程,不能直接放入繼承Thread的類。可以避免java中的單繼承的局限性。

8,匿名內部類方式實現線程的創建

public static void main(String[] args) {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					System.out.println(Thread.currentThread().getName() + i);					
				}				
			}
			
		};
		new Thread(r).start();
	}

9,線程安全

案例:電影院要賣票,我們模擬電影院的賣票過程。假設要播放的電影是  我和我的祖國,本次電影的座比特共100(本場電影只能賣100張票)

我們來模擬電影院的售票窗口,實現多個窗口同時賣 小猪佩奇這場電影票(多個窗口一起賣這100張票)需要窗口,采用線程對象來模擬;需要票,Runnable接口子類來模擬。

public class xcanq {
	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		new Thread(ticket, "窗口1").start();
		new Thread(ticket, "窗口2").start();
		new Thread(ticket, "窗口3").start();
	}
}

class Ticket implements Runnable {
	private int ticket = 100;
	@Override
	public void run() {
		while (true) {
			synchronized (this) {
				if (ticket > 0) {
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					String name = Thread.currentThread().getName();
					System.out.println(name + "正在賣" + ticket + "張票");
					ticket--;
				}
			}

		}
	}
}

10,Lock鎖

使用方法:

        public void lock();

        public void unlock();

11,線程狀態

NEW新建狀態一個線程創建以後,啟動之前,就處於該狀態。
TERMINATED消亡狀態線程執行完任務後,處於該狀態。
RUNNABLE可運行狀態線程正在整型任務,就處於該狀態。
BLOCKED阻塞狀態獲取synchronized鎖對象失敗,處於該狀態。
WAITING無限等待狀態獲取Lock鎖對象失敗,就處於該狀態。
TIMED_WAITING計時等待狀態執行sleep方法,就處於該狀態。

12,sleep和wait的區別

13,wait和notify方法

(1)wait方法

        線程不再活動,不再參與調度,進入 wait set 中,因此不會浪費 CPU 資源,也不會去競爭鎖了,這時的線程狀態即是 WAITING。

        它還要等著別的線程執行一個特別的動作,也即是“通知(notify)”在這個對象上等待的線程從wait set 中釋放出來,重新進入到調度隊列(ready queue)中。

(2)notify方法

        則選取所通知對象的 wait set 中的一個線程釋放;例如,餐館有空比特置後,等候就餐最久的顧客最先入座。

(3)notifyAll方法

        釋放所通知對象的 wait set 上的全部線程。

注意:

(1)wait方法與notify方法必須要由同一個鎖對象調用。因為:對應的鎖對象可以通過notify喚醒使用同一個鎖對象調用的wait方法後的線程。

(2)wait方法與notify方法是屬於Object類的方法的。因為:鎖對象可以是任意對象,而任意對象的所屬類都是繼承了Object類的。

(3)wait方法與notify方法必須要在同步代碼塊或者是同步函數中使用。因為:必須要通過鎖對象調用這2個方法。

14,線程的通信

案例:

        包子鋪線程生產包子,吃貨線程消費包子。當包子沒有時(包子狀態為false),吃貨線程等待,包子鋪線程生產包子(即包子狀態為true),並通知吃貨線程(解除吃貨的等待狀態),因為已經有包子了,那麼包子鋪線程進入等待狀態。

        接下來,吃貨線程能否進一步執行則取决於鎖的獲取情况。如果吃貨獲

取到鎖,那麼就執行吃包子動作,包子吃完(包子狀態為false),並通知包子鋪線程(解除包子鋪的等待狀態)吃貨線程進入等待。包子鋪線程能否進一步執行則取决於鎖的獲取情况。

定義包子類:

public class Baozi {
	String pier;
	String xianer;
	boolean flag = false;

}

定義吃貨線程:

public class Chihuo extends Thread {
	private Baozi bz;
	public Chihuo(String name, Baozi bz) {
		super(name);
		this.bz = bz;
	}

	@Override
	public void run() {
		while (true) {
			synchronized (bz) {
				if (bz.flag == true) {
					System.out.println("吃貨正在吃"+bz.pier+bz.xianer+"包子");					
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					bz.flag = false;
					bz.notify();
				} else {
					try {
						bz.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
	}
}

定義包子鋪線程:    

public class BaoZiPu extends Thread {
	private Baozi bz;
	public BaoZiPu(String name, Baozi bz) {
		super(name);
		this.bz = bz;
	}

	@Override
	public void run() {
		int count = 0;
		while (true) {
			synchronized (bz) {
				if (bz.flag == true) {
					try {
						bz.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else {
					System.out.println("包子鋪開始做包子");
					if (count % 2 == 0) {
						bz.pier = "冰皮";
						bz.xianer = "五仁";
					} else {
						bz.pier = "薄皮";
						bz.xianer = "牛肉大葱";
					}
					count++;
					bz.flag = true;
					System.out.println("包子造好了:" + bz.pier + bz.xianer);
					System.out.println("吃貨來吃吧");
					bz.notify();
				}
			}
		}
	}
}

測試線程:

public class Test {
	public static void main(String[] args) {
		Baozi bz = new Baozi();
		Chihuo ch = new Chihuo("吃貨", bz);
		BaoZiPu bzp = new BaoZiPu("包子鋪",bz);	
		bzp.start();
		ch.start();
	}
}

15,線程池概念

        其實就是一個容納多個線程的容器,其中的線程可以反複使用,省去了頻繁創建線程對象的操作,無需反複創建線程而消耗過多資源。

16,線程池的好處 

(1)降低資源消耗。减少了創建和銷毀線程的次數,每個工作線程都可以被重複利用,可執行多個任務。

(2)提高響應速度。當任務到達時,任務可以不需要的等到線程創建就能立即執行。

(3)提高線程的可管理性。可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因為消耗過多的內存,而把服務器累趴下(每個線程需要大約1MB內存,線程開的越多,消耗的內存也就越大,最後死機)

17,線程池的使用

創建線程池:public static ExecutorService newFixedThreadPool(int nThreads)

使用線程池對象:public Future<?> submit(Runnable task)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class xcc {
	public static void main(String[] args) {
		ExecutorService service = Executors.newFixedThreadPool(2);
		MyRunnable r = new MyRunnable();
		service.submit(r);		
	}
}
class MyRunnable implements Runnable {
	@Override
	public void run() {
		System.out.println("我要一個教練");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("教練來了: " + Thread.currentThread().getName());
		System.out.println("教我遊泳,交完後,教練回到了遊泳池");
	}
}

    

         

        

 

原网站

版权声明
本文为[手可摘鑫晨]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207060919160486.html