主頁 > 後端開發 > java多執行緒

java多執行緒

2023-05-29 11:20:12 後端開發

java多執行緒

行程、執行緒與多執行緒

  • 行程是執行程式的一次執行程序,是一個動態的概念,是系統支援分配的單位

  • 通常一個行程可以包含一個或多個執行緒,執行緒是CPU調度和執行的單位

  • 執行緒就是獨立執行的路徑,由cpu調度

  • 執行緒會帶來額外的開銷,如cpu調度時間,并發控制開銷

  • 每個執行緒在自己的作業記憶體中互動,記憶體控制不當會造成資料的不一致

  • main()稱之為主執行緒,為系統的入口,用于執行整個程式

  • 程式運行時,即使沒有自己創建執行緒,后臺也會有多個執行緒如主執行緒,gc執行緒

  • 很多執行緒是模擬出來的,真正的多執行緒是指有多個cpu,即多核,如服務器,如果是模擬出來的多執行緒,即只有一個cpu的情況下,在同一個時間點,cpu只能執行一個代碼,因為切換的很快,所以有了同時執行的錯覺

執行緒的三種創建方式

  1. Thread class:繼承Thread類
  2. Runnable介面:實作Runnable介面
  3. Callable介面:實作Callable介面

通過繼承Thread創建執行緒

? 注意:Thread類實作了Runnable介面

流程:

1. 自定義執行緒類繼承Thread類
2. 重寫其run()方法,撰寫程式執行體
3. 創建執行緒物件,呼叫start()方法啟動執行緒
public class MyThread extends Thread {
    @Override
    public void run() {
        //run方法執行緒體
        for (int i = 0; i < 5; i++) {
            System.out.println("run方法執行緒--"+i);
        }
    }

    public static void main(String[] args) {
        //run方法執行緒
        MyThread myThread = new MyThread();
        //啟動執行緒,另外執行緒只能啟動一次死亡之后不能重新啟動
        myThread.start();
        //主執行緒
        for (int i = 0; i < 5; i++) {
            System.out.println("主執行緒--"+i);
        }

    }
}

/*out:
主執行緒--0
run方法執行緒--0
主執行緒--1
run方法執行緒--1
主執行緒--2
run方法執行緒--2
主執行緒--3
run方法執行緒--3
主執行緒--4
run方法執行緒--4

注意:輸出結果不唯一,每次執行結果不一樣
執行緒開啟不一定立即執行,是由cpu調度執行

實作Runnable介面創建執行緒

1. 自定義執行緒類實作Runnable介面
2. 重寫其run()方法,撰寫程式執行體
3. 創建該實作類物件,創建Thread執行緒物件(或者創建Thread物件),并且向Thread物件丟入Runnable實作類(代理方法)
public class MyThread implements  Runnable {
    @Override
    public void run() {
        //run方法執行緒體
        for (int i = 0; i < 5; i++) {
            System.out.println("run方法執行緒--"+i);
        }
    }

    public static void main(String[] args) {
        //run方法執行緒
        MyThread myThread = new MyThread();
        //靜態代理
        new Thread(myThread).start();
        //主執行緒
        for (int i = 0; i < 5; i++) {
            System.out.println("主執行緒--"+i);
        }

    }
}

/*
主執行緒--0
run方法執行緒--0
主執行緒--1
run方法執行緒--1
主執行緒--2
主執行緒--3
run方法執行緒--2
主執行緒--4
run方法執行緒--3
run方法執行緒--4

相比于前一種更推薦本方法:避免單繼承局限,靈活方便,方便一個物件被多個執行緒使用

例如:

public class MyThread implements  Runnable {
    private  int number=10;
    @Override
    public void run() {
       while (true){
           if(number<=0){
               break;
           }
           //執行緒休眠,防止cpu速度太快瞬間把票搶完
           try {
               Thread.sleep(10);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
//當前執行緒名字
           System.out.println(Thread.currentThread().getName()+"--"+number--);

       }
    }

    public static void main(String[] args) {
        //run方法執行緒
        MyThread myThread = new MyThread();
        //第二個引數為執行緒名字
        new Thread(myThread,"李").start();
        new Thread(myThread,"馬").start();
        new Thread(myThread,"王").start();


    }
}

/*
馬--9
王--10
李--10
馬--8
李--8
王--8
馬--7
王--6
李--6
王--5
馬--4
李--3
李--0
馬--2
王--1


注意:至于為什么出現兩個人得到同一個數字,或者出現0,則是一些經典的執行緒同步問題

實作Callable介面創建執行緒

步驟:

  • 實作Callable介面,需要回傳值型別
  • 重寫call方法,需要拋出例外
  • 創建目標物件
  • 創建執行服務
  • 提交執行
  • 獲取結果
  • 關閉服務
//<>中填寫回傳值型別(下面call方法的回傳值)
public class MyThread implements Callable<Boolean> {
    //重寫call方法,回傳值保持和<>中的一樣
    @Override
    public Boolean call() throws Exception {\
        //具體執行緒操作寫在這里
        return false;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        MyThread myThread3 = new MyThread();
        //創建執行服務:newFixedThreadPool執行緒池,引數為執行緒池大小
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //提交執行:<>中型別就是call的回傳型別
        Future<Boolean> r1 = ser.submit(myThread1);
        Future<Boolean> r2 = ser.submit(myThread2);
        Future<Boolean> r3 = ser.submit(myThread3);
        //獲取結果:call()回傳值
        Boolean rs1 = r1.get();
        Boolean rs2 = r2.get();
        Boolean rs3 = r3.get();
        //關閉服務
        ser.shutdownNow();
    }
}

好處:

  • 可以定義回傳值

  • 可以拋出例外

靜態代理

代理就是兩個物件實作同一個介面,一個是代理物件一個是真實物件,通過代理物件執行真實物件方法,具體方法:代理物件和真實物件實作同一個介面,創建代理物件同時向其中傳入一個真實物件,在代理物件中操作真實物件,在外部呼叫操作代理物件就能夠操作真實物件,

例如前面通過實作Runnable介面創建執行緒就運用了靜態代理

	//MyThread是Runnable介面的實作類
        MyThread myThread = new MyThread();
        //靜態代理
        new Thread(myThread).start();

好處:

  • 代理物件可以在真實物件基礎上做很多拓展
  • 真實物件專注于自己,專注于核心方法

Lambda運算式

為什么使用它?

  • 避免匿名內部類過多
  • 讓代碼看起來更加簡潔
  • 去掉無意義代碼留下核心邏輯

函式式介面

  • 理解函式式介面是學習Lambda運算式的關機
  • 函式式介面的定義:
    1. 任何介面,如果只包含唯一一個抽象方法,那么它就是函式式介面
    2. 對于函式式介面,我們可以通過lamda運算式來創建該介面的物件

怎么使用?

public interface MyInterface {
    void lambda();
}
class main {
    public static void main(String[] args) {
//        無參且一行
        MyInterface myInterface =() -> System.out.println("hello world");
//        有引數a
//        MyInterface myInterface =a  -> System.out.println("hello world");
//        多行
//        MyInterface myInterface1 = ()->{
//            System.out.println();
//            System.out.println()
//        };
        
//        上述代碼完全類似下面的匿名內部類
//        MyInterface myInterface1 = new MyInterface() {
//            @Override
//            public void lambda() {
//                System.out.println("hello world");
//            }
//        };
    }
}

//out:hello world

執行緒的五大狀態

執行緒方法

停止執行緒

  • 可以但不推薦使用JDK提供的stop()、destroy()方法,已經廢棄
  • 推薦執行緒自己停下來
  • 建議使用一個標志位進行終止變數,當flag=false終止執行緒運行
public class MyThread implements  Runnable {
    private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while (flag){
            System.out.println("run........Thread"+i++);
        }
    }
    public void stop(){
        this.flag = false;
        System.out.println("執行緒已經停止");
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread).start();
        for (int i = 0; i < 10; i++) {
            //不加這一句的話回圈速度太快以至于執行緒還沒運行
            System.out.println("main---"+i);
            if(i==5){
                //呼叫自己寫的stop方法
                myThread.stop();
            }
        }
    }
}

/*
main---0
run........Thread0
main---1
run........Thread1
main---2
run........Thread2
main---3
run........Thread3
main---4
run........Thread4
main---5
run........Thread5
執行緒已經停止
main---6
main---7
main---8
main---9

執行緒休眠

  • sleep()指定當前執行緒阻塞的毫秒數
  • 運行狀態轉為阻塞狀態
  • sleep存在例外InterruptedException
  • sleep時間到達后進入就緒狀態
  • 其可以模擬網路延時,倒計時等
  • 每一個物件都有一個鎖,sleep不會釋放鎖

沒啥可說的固定寫法:Thread.sleep()

執行緒禮讓

  • 即讓當前正在執行的執行緒暫停,但不阻塞
  • 把執行緒從運行轉為就緒狀態
  • 讓cpu重新調度,禮讓不一定成功,看cpu心情
  • 固定寫法:Thread.yield();
public class MyThread implements  Runnable {
    private boolean flag = true;
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"開始執行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"完成執行");

    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        MyThread myThread1 = new MyThread();
        new Thread(myThread,"a").start();
        new Thread(myThread1,"b").start();

    }
}
/*
a開始執行
b開始執行
b完成執行
a完成執行

執行緒強制執行

  • Join合并執行緒,待此執行緒完成后,才去執行其他執行緒
  • 可以看作插隊
public class MyThread implements  Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("VIP駕到通通閃開!"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread1 = new MyThread();
        Thread thread1 = new Thread(myThread1, "vip");
        //主執行緒
        for (int i = 0; i < 10; i++) {
            if(i==5){
                thread1.start();
                thread1.join();
            }
            System.out.println("我是一個主執行緒"+i);

        }

    }
}

/*
我是一個主執行緒0
我是一個主執行緒1
我是一個主執行緒2
我是一個主執行緒3
我是一個主執行緒4
VIP駕到通通閃開!0
VIP駕到通通閃開!1
VIP駕到通通閃開!2
VIP駕到通通閃開!3
VIP駕到通通閃開!4
我是一個主執行緒5
我是一個主執行緒6
我是一個主執行緒7
我是一個主執行緒8
我是一個主執行緒9

執行緒狀態觀測

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("////////");
        });
        //觀測狀態
        Thread.State state = thread.getState();
        System.out.println(state);
//        啟動執行緒
        thread.start();
        state = thread.getState();
        System.out.println(state);
//        只要執行緒不終止一直輸出狀態
        while (state != Thread.State.TERMINATED){
            Thread.sleep(1000);
            state = thread.getState();
            System.out.println(state);
        }
    }

/*
NEW
RUNNABLE
RUNNABLE
TIMED_WAITING
TIMED_WAITING
RUNNABLE
TIMED_WAITING
////////
TERMINATED

執行緒優先級

  • 執行緒優先級用數字表示:Thread.MIN_PRIORITY=1;

    ? Thread.MAX_PRIORITY = 10;

    ? Thread.NORM_PRIORITY = 5;

    上面為最小最大正常優先級,均為常量

  • 可以使用以下方式改變或者獲取優先級:
    1. .getPrioriyt
    1. .setPriority(int xxx)

  • 另外,優先級高并不是一定先執行,而是相對來說權重更高,到底先還是后看cpu調度

public class MyThread implements  Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) throws InterruptedException {
        //主執行緒優先級:主執行緒優先級無法修改
        System.out.println(Thread.currentThread().getName()+"-----"+Thread.currentThread().getPriority());
        MyThread myThread = new MyThread();
        Thread t1 = new Thread(myThread,"t1");
        Thread t2 = new Thread(myThread,"t2");
        Thread t3 = new Thread(myThread,"t3");
        Thread t4 = new Thread(myThread,"t4");
        Thread t5 = new Thread(myThread,"t5");

//        一定要注意:先設定優先級再啟動否則沒用
        t1.start();
        t2.setPriority(1);
        t2.start();
        //設定為最大優先級
        t3.setPriority(Thread.MAX_PRIORITY);
        t3.start();

    }
}
/*
main-----5
t3
t2
t1

守護執行緒

  • daemon
  • 執行緒分為用戶執行緒和守護執行緒
  • 虛擬機必須確保用戶執行緒執行完畢
  • 虛擬機不用等待守護執行緒完畢
  • 守護執行緒如后臺記錄操作日志、監控記憶體、垃圾回收等待
  • 守護執行緒:字面意思守護用戶執行緒,虛擬機無視是否還有守護執行緒存在,當用戶執行緒結束時虛擬機關閉
Thread thread = new Thread();
//默認是false代表用戶執行緒,設定為true表示守護執行緒
thread.setDaemon(true);

執行緒同步

  • 就是多個執行緒操作同一個資源

  • 執行緒同步其實就是一個等待機制,多個需要同時訪問物件的執行緒進入物件等待池形成佇列

  • 并發:同一個物件被多個執行緒操作,如買票

  • 佇列和鎖保障執行緒安全性

  • 為了保證資料在方法中被訪問時的正確性,在訪問時加入鎖機制synchronized

  • 與此同時當一個執行緒獲得物件的排它鎖,獨占資源,其他執行緒必須等待使用后釋放鎖即可,可能存在以下問題:

執行緒同步操作多種不安全問題,具體可以看上面實作Runnable介面創建執行緒的例子

synchronized(鎖)

  • 針對上面所說的問題:我們可以用鎖來解決,即synchronized關鍵字,它包括方法和塊兩大用法

  • 同步方法,synchronized方法控制對“物件”的訪問,每個物件對應一把鎖,每個synchronized方法都必須獲得呼叫該方法的物件的鎖才能執行,否則阻塞,方法一旦執行就會獨占該鎖,直到該方法回傳,缺陷:若將一個大方法申明為synchronized將會影響效率

  • 同步塊:synchronized(obj){} obj稱之為同步監視器,其可以是任何物件,但是推薦共享資源作為同步監視器,另外同步方法不用同步監視器因為其同步監視器就是this,就是這個物件本身,或者class

  • 同步監視器執行程序:
    1. 第一個執行緒訪問,鎖定同步監視器
    2. 第二個執行緒訪問,發現已經被鎖定,無法訪問
    3. 第一個執行緒訪問完畢,解鎖同步監視器
    4. 第二個執行緒訪問,發現同步監視器沒有鎖,然后鎖定并且訪問

使用同步方法解決問題:

public class MyThread implements  Runnable {
    private  int number=10;
    private  boolean flag = true;
    @Override
    public  void run() {
        while (flag) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            buy();
        }
    }
    //上鎖,run方法也可以鎖
    public synchronized void buy() {
        if (number < 1) {
            flag=false;
            return;
        }
            System.out.println(Thread.currentThread().getName() + "--" + number--);
        }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread,"李").start();
        new Thread(myThread,"馬").start();
        new Thread(myThread,"王").start();
    }
}
/*
李--10
王--9
馬--8
馬--7
李--6
王--5
馬--4
李--3
王--2
馬--1

鎖塊:

public class MyThread implements  Runnable {
    private  int number=10;
    private  boolean flag = true;
    @Override
    public  void run() {
        while (flag) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //同步塊,()填變化的量必須是參考型別,鎖定的就是傳入引數
            synchronized (Integer.valueOf(number)){
                if (number < 1) {
                    flag=false;
                }
                else {
                    System.out.println(Thread.currentThread().getName() + "--" + number--);
                }
            }
            }
        }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread,"李").start();
        new Thread(myThread,"馬").start();
        new Thread(myThread,"王").start();
    }
}

/*
馬--10
王--9
李--8
李--7
王--6
馬--5
馬--4
李--3
王--2
馬--1

CopyOnWriteArrayList

//執行緒安全的arraylist
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 1000; i++) {
    new Thread(()->{
        list.add(Thread.currentThread().getName());
    }).start();
}
Thread.sleep(3000);
System.out.println(list.size());
//1000

死鎖

多個執行緒各自占有一些共享資源,同時互相等待對方占有資源,從而導致兩個或多個執行緒都在等待對方釋放資源停止執行的情況,

某一個同步塊同時擁有兩個以上物件的鎖,就可能出現死鎖

 //當mirror和lipstick都只有一份時
            //獲得mirror
            synchronized (mirror){
//                獲得了mirror,此時lipstick被另外一個執行緒占據等待
//                其釋放,與此同時占據lipstick的執行緒也在等待它釋放mirror
//                  于是死鎖發生了
                synchronized (lipstick){
                    
                }
            }

產生死鎖的必要條件

Lock(鎖)

  • JDK5.0開始,java提供更加強大的執行緒同步機制--通過顯式定義同步鎖物件來實作同步,同步鎖使用Lock充當
  • 每次只能有一個執行緒對Lock物件加鎖,執行緒開始訪問共享資源之前應當先獲得Lock鎖
  • ReentranLock類實作了Lock,它擁有與synchronized相同的并發性和記憶體語意,在實作執行緒安全的控制中,比較常用的是ReentrantLock,可以顯式加鎖、釋放鎖
public class MyThread implements  Runnable {
    private static Integer number=10;
    private  boolean flag = true;
    //定義lock鎖
    private final  ReentrantLock lock = new ReentrantLock();

    @Override
    public  void run() {
        while (flag) {
            try {
                Thread.sleep(100);
                lock.lock();//加鎖,上鎖區域就是lock到unlock區域
                if (number < 1) {
                    flag=false;
                }
                else {
                    System.out.println(Thread.currentThread().getName() + "--" +number--);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //解鎖
                lock.unlock();
            }

            }
        }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread,"李").start();
        new Thread(myThread,"馬").start();
        new Thread(myThread,"王").start();
    }
}
/*
馬--10
王--9
李--8
李--7
王--6
馬--5
王--4
李--3
馬--2
馬--1

執行緒協作--生產者消費者問題

生產者消費者問題:生產者消費者共享一個資源,并且生產者和消費者之間相互依賴,互為條件,作業系統學過的不想多說具體如下:

下面兩個解決辦法后面有具體演示

解決方法1:

解決方法二:信號燈法

java提供了幾個方法解決執行緒之間的通信問題:

注意:以下均是Object類的方法,都只能在同步方法或者同步代碼塊中使用,否則會拋出例外,另外sleep不會釋放鎖,wait會釋放鎖

解決方法一:管程法

public class Test {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Producer(container).start();
        new Consumer().start();

    }
}

//生產者
class  Producer extends  Thread{
    //緩沖區
  static SynContainer container;

    public Producer(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            container.push(new Chicken(i));
            System.out.println("生產了第"+i+"只雞");

        }
    }
}

//消費者
class Consumer extends  Thread{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("消費了第"+  Producer.container.pop().id+"只雞");
        }
    }
}

//產品
class Chicken{
    int id;

    public Chicken(int id) {
        this.id = id;
    }
}

//緩沖區
class  SynContainer{
    //需要一個容器大小
    Chicken[]  chickens = new Chicken[10];
//    容器計數器
    int count = 0;
    //生產者放入產品
    public synchronized void  push(Chicken chicken){
        //如果容器滿了,等待消費者消費
        if(count==chickens.length){
            //通知消費者消費,生成等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else {
            //如果沒有滿,我們就需要丟入產品
            chickens[count] = chicken;
            count++;
        }
//        通知消費者可以消費了
        this.notifyAll();
    }

    //消費者消費產品
    public synchronized  Chicken pop()  {
        //判斷是否有產品
        if(count==0){
//            等待生產者生產
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

//        存在產品開始消費
        count--;
        Chicken chicken = chickens[count];

//        吃完了通知生產者生產
        this.notifyAll();
        return  chicken;
    }
}
/*
生產了第0只雞
消費了第0只雞
生產了第1只雞
生產了第2只雞
消費了第1只雞
生產了第3只雞
消費了第3只雞
生產了第4只雞
消費了第4只雞
消費了第2只雞

上面實作的存在一定問題,但是要傳達的思想就這樣

解決方法二:信號燈法

public class Test {
    public static void main(String[] args) {
        TV tv =new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

//生產者
class  Player extends  Thread{
    TV tv;

    public Player(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            if(i%2==0){
                this.tv.play("x節目播放中");
            }
            else {
                this.tv.play("y節目播放中");
            }
        }
    }
}

//消費者
class Watcher extends  Thread{
    TV tv;

    public Watcher(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            tv.watch();
        }
    }
}

//產品
class TV{
    //演員表演,觀眾等待 T
    //觀眾觀看,演員表演  F
    String voice;//表演的節目
    boolean flag = true;
    public synchronized void play(String voice){
        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演員表演了:"+voice);
        this.notifyAll();
        this.voice = voice;
        this.flag = !this.flag;
    }
    public  synchronized  void  watch(){
        if(flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
            System.out.println("觀看了"+voice);
//            通知演員表演
            this.notifyAll();
            this.flag = !this.flag;
        }
    }

/*
演員表演了:x節目播放中
觀看了x節目播放中
演員表演了:y節目播放中
觀看了y節目播放中
演員表演了:x節目播放中
觀看了x節目播放中
演員表演了:y節目播放中
觀看了y節目播放中
演員表演了:x節目播放中
觀看了x節目播放中

執行緒池

  • 經常創建和銷毀、使用量大的資源,對性能影響很大

  • 思路:提前創建好多個執行緒,放入執行緒池,使用時直接獲取,使用完放回池中,可以避免頻繁創建銷毀、實作重復利用,

  • 好處:

    • 提高回應速度
    • 降低資源消耗
    • 便于執行緒管理
      • corePoolSize:核心池大小
      • maximumPoolSize:最大執行緒數
      • keepAliveTime:執行緒沒有任務時最多保持多少時間后終結
  • 相關api:

    • ExecutorService :真正的執行緒池介面,常見子類ThreadPoolExecutor
      • 相關方法:
  • Executors:工具類,用于創建并回傳不同型別的執行緒池

public class MyThread implements  Runnable {
    private int number=10;
    private  boolean flag = true;
    @Override
    public  void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        //創建執行緒池,引數為大小
        ExecutorService service = Executors.newFixedThreadPool(10);
        //執行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
//        關閉鏈接
        service.shutdownNow();
    }
}

/*
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/553686.html

標籤:Java

上一篇:關于切片引數傳遞的問題

下一篇:返回列表

標籤雲
其他(159902) Python(38178) JavaScript(25460) Java(18142) C(15232) 區塊鏈(8268) C#(7972) AI(7469) 爪哇(7425) MySQL(7214) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5873) 数组(5741) R(5409) Linux(5344) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4578) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2434) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1977) 功能(1967) Web開發(1951) HtmlCss(1949) C++(1925) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1878) .NETCore(1862) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • java多執行緒

    # java多執行緒 ## 行程、執行緒與多執行緒 - 行程是執行程式的一次執行程序,是一個動態的概念,是系統支援分配的單位 - 通常一個行程可以包含一個或多個執行緒。執行緒是CPU調度和執行的單位 - 執行緒就是獨立執行的路徑,由cpu調度 - 執行緒會帶來額外的開銷,如cpu調度時間,并發控制開銷 - 每個線 ......

    uj5u.com 2023-05-29 11:20:12 more
  • 關于切片引數傳遞的問題

    前言:在 Golang 中函式之間傳遞變數時總是以值的方式傳遞的,無論是 int,string,bool,array 這樣的內置型別(或者說原始的型別),還是 slice,channel,map 這樣的參考型別,在函式間傳遞變數時,都是以值的方式傳遞,也就是說傳遞的都是值的副本。 在使用ioutil ......

    uj5u.com 2023-05-29 11:12:45 more
  • 驅動開發:內核決議記憶體四級頁表

    當今作業系統普遍采用64位架構,CPU最大尋址能力雖然達到了64位,但其實僅僅只是用到了48位進行尋址,其記憶體管理采用了`9-9-9-9-12`的分頁模式,`9-9-9-9-12`分頁表示物理地址擁有四級頁表,微軟將這四級依次命名為PXE、PPE、PDE、PTE這四項。關于記憶體管理和分頁模式,不同的... ......

    uj5u.com 2023-05-29 10:57:11 more
  • 計算機網路面試八股文

    ## 網路分層結構 計算機網路體系大致分為三種,OSI七層模型、TCP/IP四層模型和五層模型。一般面試的時候考察比較多的是五層模型。最全面的Java面試網站:[最全面的Java面試網站](https://topjavaer.cn) ![](http://img.topjavaer.cn/img/t ......

    uj5u.com 2023-05-29 07:47:54 more
  • Java的Object類的方法

    Java的Object類是所有類的根類,它提供了一些通用的方法。下面是一些常用的Object類方法: 1. equals(Object obj):判斷當前物件是否與給定物件相等。默認情況下,equals方法比較的是物件的參考,但可以通過在具體類中重寫equals方法來改變其比較行為。 2. hash ......

    uj5u.com 2023-05-29 07:47:29 more
  • Python 使用ConfigParser操作ini組態檔

    ini 組態檔格式如下 要求:ini 檔案必須是GBK編碼,如果是UTF-8編碼,python讀取組態檔會報錯。 # 這里是注釋內容 # [FY12361] #婦幼保健介面服務埠 serverIP=192.168.1.11 serverPort=8400 [SM] #國產SM加密服務埠 se ......

    uj5u.com 2023-05-29 07:47:23 more
  • Rust Web 全堆疊開發之 Actix 嘗鮮并構建REST API

    # Rust Web 全堆疊開發之 Actix 嘗鮮并構建REST API ## 一、Actix 嘗鮮 ### 需要使用的crate - actix-web v4.3.1 - actix-rt v2.8.0 ```bash ~ via 🅒 base ? cd rust ~/rust via 🅒 b ......

    uj5u.com 2023-05-29 07:47:16 more
  • QT 繪制波形圖、頻譜圖、瀑布圖、星座圖、眼圖、語圖

    最近在學中頻信號處理的一些東西,順便用 QT 寫了一個小工具,可以顯示信號的時域波形圖、幅度譜、功率譜、二次方譜、四次方譜、八次方譜、瞬時包絡、瞬時頻率、瞬時相位、非線性瞬時相位、瞬時幅度直方圖、瞬時頻率直方圖、瞬時相位直方圖、眼圖、星座圖、語譜圖、瀑布圖。 ......

    uj5u.com 2023-05-29 07:46:15 more
  • 【VS Code+Qt6】拖放操作

    由于老周的示例代碼都是用 VS Code + CMake + Qt 寫的,為了不誤匯入,在標題中還是加上“VS Code”好一些。 上次咱們研究了剪貼板的基本用法,也了解了叫 QMimeData 的重要類。為啥要強調這個類?因為接下來扯到的拖放操作也是和它有關系。哦,對了,咱們先避開一下主題,關于剪 ......

    uj5u.com 2023-05-29 07:45:36 more
  • Python asyncio之協程學習總結

    ## 實踐環境 Python 3.6.2 ## 什么是協程 **協程**(Coroutine)一種電腦程式組件,該程式組件通過允許暫停和恢復任務,為非搶占式多任務生成子程式。**協程**也可以簡單理解為協作的程式,通過協同多任務處理實作并發的函式的變種(一種可以支持中斷的函式)。 下面,我們通過日常 ......

    uj5u.com 2023-05-29 07:45:19 more