java多線程

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();

    }
}
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容