1.基礎概念
- 程序:是為了完成特定任務、用某種語言編寫的一組指令集合,指一段靜態(tài)的代碼, 是一個靜態(tài)概念。
- 進程:是具有一定獨立功能程序的執(zhí)行過程,是操作系統(tǒng)進行資源分配和調(diào)度的基本單位也就是說進程是可以獨立運行的一段程序。
1. 進程是程序的一次執(zhí)行過程,通常是一個可執(zhí)行程序在內(nèi)存中的一個完整副本,每個進程都有自己的數(shù)據(jù)段,棧段,和代碼段。是一個動態(tài)概念。
2. 多進程是指操作系統(tǒng)能同時運行多個程序。 - 線程是進程中一個獨立執(zhí)行的線索,是進程中的一個實體,是CPU調(diào)度和分派的基本單位,是比進程更小的能獨立運行的基本單位
1. 線程是進程中一個實體,用來描述線程的執(zhí)行,它負責執(zhí)行包括在進程的地址空間中的代碼,創(chuàng)建一個進程時候他的第一個線程稱為主線程是由系統(tǒng)自動生產(chǎn)的。
2. 進程
- 每個進程都有獨立的代碼和數(shù)據(jù)空間(進程上下文),進程間的切換會有較大的開銷,一個進程包含1~n個線程。(進程是資源分配的最小單位)
- 同一類線程共享代碼空間和數(shù)據(jù)空間,每個線程擁有自己的運行棧和程序計數(shù)器,線程切換的開銷較小。
2.1 進程啟動的方法
//方法1:
public class Test01 {
public static void main(String[] args) throws IOException {
ProcessBuilder pb = new ProcessBuilder("cmd", "/c" ,"ipconfig/all");
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(),"GBK"));
String s=null;
while((s = reader.readLine())!=null){
System.out.println(s);
}
}
}
//方法2:
public class Test02 {
public static void main(String[] args) throws IOException {
String path = "cmd"+" /c"+"ipconfig/all";
Process process = Runtime.getRuntime().exec(path);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(),"GBK"));
String s=null;
while((s = reader.readLine())!=null){
System.out.println(s);
}
}
}
2.2 進程的三大特征
- 獨立新
- 動態(tài)性
- 并發(fā)性
僵尸進程:是指當子線程比父線程先結束,而父進程沒有回收子線程,沒有回收子線程所占的資源,此時子進程稱為僵尸進程,如果父進程先退出,子進程被Init接管,子進程退出侯init會釋放其所占的資源----》是對系統(tǒng)資源的浪費,必須解決。**
孤兒進程:是一個父進程退出,而一個或者多個子進程還在執(zhí)行那么這些子進程會成為孤兒進程,孤兒進程將被init方法所收養(yǎng)并由init完成對其資源釋放的工作,沒有什么危害
2.3 并發(fā)與并行
- 并發(fā):通過CPU調(diào)度算法,讓用戶看上去同時執(zhí)行,實際從CPU操作層面不是真正的同時執(zhí)行。
- 并行:多個CPU實列或者多臺機器同時執(zhí)行一段處理邏輯,是真正的同時執(zhí)行
2.4 主線程
線程是進程中的一個實體,用來描述進程的執(zhí)行,他負責執(zhí)行包括在進程地址空間之中的代碼,創(chuàng)建一個線程的時候,他的第一個線程稱為主線程,是由系統(tǒng)自動創(chuàng)建的
- 他是產(chǎn)生其他子線程的線程
- 通常最后執(zhí)行完畢,這里不絕對
進程中線程之間的關系
線程不像進程,一個進程之中的線程沒有父子之分都是平級的,即當一個線程退出的時候不會影響另一個,但是所謂的主線程mian其入口代碼是類似這樣調(diào)用的exit(main())當main線程執(zhí)行完畢之后會調(diào)用exit()會使整個進程終止,那么所有線程自然會退出。
進程與線程的關系- 一個進程可以有多個線程,至少有一個主線程,一個線程只能屬于一個進程
- 資源分配給進程,同一個進程中的所有線程共享該資源
- 線程在執(zhí)行過程中需要協(xié)作同步
- 線程是進程內(nèi)可調(diào)度的一個執(zhí)行單元,也是進程內(nèi)可調(diào)度的實體。
線程和進程的區(qū)別
- 調(diào)度 :線程是CPU調(diào)度和分配的基本單元,進程是操作系統(tǒng)分配和調(diào)度的基本單元。
- 并發(fā)性:不僅進程之間可以并發(fā)執(zhí)行,同一個進程的多個線程之間也可以并發(fā)執(zhí)行,一個進程至少有一個線程(單進程單線程),一個線程必須隸屬于某個進程。
- 擁有資源:進程是擁有資源的一個單位,線程不擁有資源,但是可以訪問隸屬與進程的資源。
- 進程和線程最大的區(qū)別在于:進程是由操作系統(tǒng)來控制的,而線程是由進程來控制的。
- 線程本身的數(shù)據(jù)通常只有寄存器數(shù)據(jù),以及一個程序執(zhí)行時使用的堆棧,所以線程的切換比進程切換的負擔要小
- 多個進程的內(nèi)部數(shù)據(jù)和狀態(tài)都是完全獨立的,而多線程是共享一塊內(nèi)存空間和一組系統(tǒng)資源,有可能互相影響
3. 線程創(chuàng)建的方式
3.1 繼承Thread類
- Tread類本質(zhì)上也是實現(xiàn)了Runable接口的一個實例,代表一個線程實例。
class Test{
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
System.out.println("這是創(chuàng)建線程的第一種方式");
}
}
- 啟動線程的唯一方法就是調(diào)用Thread類的start()實例方法,不能直接調(diào)用run(),start()方法是一個native方法,它代表啟動一個線程并執(zhí)行run方法,這種方法最大的限制就是java是單根繼承。
3.2 實現(xiàn)Runable接口
@FunctionalInterface //函數(shù)是接口 ,可以使用Lambda表達式
public interface Runnable {
public abstract void run();
}
使用例子:
//匿名內(nèi)部類形式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("匿名內(nèi)部類形式");
}
}).start();
//lambda表達式形式
new Thread(()->{
System.out.println("Lambda表達式形式");
}).start();
3.3 使用Callable和Future接口創(chuàng)建線程

圖片.png
使用好處就是可以有 返回值可以拋出異常
@FunctionalInterface//函數(shù)式接口
public interface Callable<V> {//V代表泛型
V call() throws Exception;//可拋出異常
}
public interface Future<V>{//用于獲取Callable接口中的call方法的執(zhí)行結果
boolean cancel(boolean mayIntersupteIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException;
}
//繼承Runable接口和Futrue接口
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
//實現(xiàn)RunableFutrue接口
public class FutureTask<V> implements RunnableFuture<V>

圖片.png
注意:FutureTask實現(xiàn)了Future和Runnable接口,所以new Thread(futureTask),當執(zhí)行thread.start()方法時會自動調(diào)用Callable接口實現(xiàn)中的call方法。當調(diào)futureTask.get()方法時可以獲取對應的線程對象的執(zhí)行結果,如果線程并沒有返回時,當前線程阻塞等待。
3.4 使用線程池
享元模式
享元模式Flyweight Pattern主要用于減少創(chuàng)建對象的數(shù)量,以減少內(nèi)存占用和提高性能。這種類型的設計模式屬于結構型模式,它提供了減少對象數(shù)量從而改善應用所需的對象結構的方式。
優(yōu)點:大大減少對象的創(chuàng)建,降低系統(tǒng)內(nèi)存的使用,以提高程序執(zhí)行的效率;
缺點:提高了系統(tǒng)的復雜度,需要分離出外部狀態(tài)和內(nèi)部狀態(tài),而且外部狀態(tài)具有固有化的性質(zhì),不應該隨著內(nèi)部狀態(tài)的變化而變化,否則會造成系統(tǒng)的混亂。
public class Test {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(4);
Thread[] threads = new Thread[10];
for(int i = 0;i<10;i++){
threads[i] = new Thread(()->{
System.out.println("線程執(zhí)行");
});
;
service.submit(threads[i]);
}
service.shutdown();
}
}