主頁 >  其他 > Java多執行緒技術概述(知識點整理)

Java多執行緒技術概述(知識點整理)

2021-02-20 10:46:17 其他

文章目錄

      • 多執行緒技術概述
        • 執行緒和行程
        • 執行緒調度
        • 同步與異步
        • 并發與并行
        • 兩種創建方式
          • Thread
          • Runnable
        • 執行緒常用方法
          • getName()與setName()
          • sleep()
        • 執行緒阻塞
        • 執行緒中斷
        • 守護執行緒
        • 執行緒安全問題
        • synchronized(執行緒同步)
          • 1、同步代碼塊
          • 2、同步方法
          • 3、顯示鎖(Lock)
        • 公平鎖和非公平鎖
        • 執行緒死鎖
        • 多執行緒通信問題
        • 執行緒的六種狀態
        • 特殊的創建方法
          • Callable和Runnable的區別
            • Runnable與Callable的相同點
            • Runnable與Callable的不同點
        • 執行緒池概述
          • 執行緒池Executors
          • 執行緒池的好處
          • 執行緒池原理圖
          • Java中的四種執行緒池 .ExecutorService
            • 1、快取執行緒池
            • 2、定長執行緒池
            • 3、單執行緒執行緒池
            • 4、周期性任務定長執行緒池
        • Lambda運算式

多執行緒技術概述

執行緒和行程

行程:

  • 是指一個記憶體中運行的應用程式,每個行程都有一個獨立的記憶體空間,并且行程互不共享記憶體空間,除非通過特殊手段,程式就是行程,例如:電腦的各個圖示

執行緒:

  • 是行程中的一個執行路徑,共享一個記憶體空間,執行緒之間可以自由切換,并發執行,一個行程最少有一個執行緒,
  • 執行緒實際上是在行程基礎之上的進一步劃分,一個行程啟動之后,里面的若干執行路徑又可以劃分成若干個執行緒,
  • 用到哪一個哪一個被喚醒,例如:和多人聊天 sleep 生產者和消費者

執行緒和行程的關系:一個行程由多個執行緒支撐運行,

執行緒調度

分時調度

  • 所有執行緒輪流使用CPU的使用權,平均分配每個執行緒占用CPU的時間,

搶占式調度

  • 優先讓優先級高的執行緒使用CPU,如果執行緒的優先級相同,那么會隨機選擇一個(執行緒隨機性),Java使用的為搶占式呼叫,

  • CPU使用搶占式調度模式在多個執行緒間進行著高速的切換,對于CPU的一個核心而言,某個時刻,只能執行一個執行緒,而CPU在多個執行緒間切換的速度相對于我們的感覺要快,看上去就是在同一時刻運行,其實,多執行緒程式并不能提高程式的運行速度,但能提高程式的運行效率,讓CPU的使用率更高,

同步與異步

同步:排隊執行,效率低但是安全,

異步:同時執行,效率高但是資料不安全,

并發與并行

并發:指兩個或多個事件在同一個時間段內發生,

并行:指兩個或多個事件在同一時刻發生(同時發生),

兩種創建方式

Thread
public static void main(String[] args){
    MyThread m = new MyThread();
    m.start();
    for(int i=0;i<10;i++){
        System.out.println("汗滴禾下土"+i);
    }
}
class MyThread extends Thread{
    //run方法就是執行緒要執行的任務方法
    @Override
    public void run(){
        //這里的代碼 就是一條新的執行路徑
        //這個執行路徑的觸發方式,不是呼叫run方法,而是通過thread物件的start來啟動任務
        for(int i=0;i<10;i++){
            System.out.println("鋤禾日當午"+i);
        }
    }
}
//結果主程式和執行緒的輸出陳述句同時執行,

執行流程圖如下所示:

在這里插入圖片描述

注意:每個執行緒都擁有自己的堆疊空間,共用一份堆記憶體,

Runnable
public static void main(String[] args){
    //實作Runnable
    //1.創建一個任務物件
    MyRunnable r = new MyRunnable();
    //2.創建一個執行緒,并為其分配一個任務
    Thread t = new Thread(r);
    //3.執行這個執行緒
    t.start();
    for(int i=0;i<10;i++){
        System.out.println("疑是地上霜"+i);
    }
}
//這是用于給執行緒執行的任務
class MyRunnable implements Runnable{
    @Override
    public void run(){
        //執行緒的任務
        for(int i=0;i<10;i++){
            System.out.println("床前明月光"+i);
        }
    }
}

實作Runnable與繼承Thread相比有如下優勢:

  1. 通過創建任務,然后給執行緒分配的方式來實作的多執行緒,更適合多個執行緒同時執行相同任務的情況;
  2. 可以避免單繼承所帶來的局限性;
  3. 任務與執行緒本身是分離的,提高了程式的健壯性;
  4. 執行緒池技術,只接受Runnable型別的任務,不接受Thread型別的執行緒;
public static void main(String[] args){
    new Thread(){//通過匿名內部類的方式創建一個執行緒
        @Override
        public void run(){
            for(int i=0;i<10;i++){
                System.out.println("一二三四五")
            }
        }
    }.start();
    for(int i=0;i<10;i++){
        System.out.println("六七八九十"+i);
    }
}

執行緒常用方法

getName()與setName()

獲取執行緒名稱與設定執行緒名稱:

public static void main(String[] args){
    System.out.println(Thread.currentThread().getName());//輸出:main
    new Thread(new MyRunnable()).start();//輸出:Thread-0
    new Thread(new MyRunnable()).start();//輸出:Thread-1
    new Thread(new MyRunnable()).start();//輸出:Thread-2
    new Thread(new MyRunnable(),"鋤禾日當午").start;//輸出:鋤禾日當午     注意,這個方法是給執行緒命名
    Thread t = new Thread(new MyRunnable());//另一種命名的方法
    t.setName("鋤禾日當午");
    t.start();
}
static class MyRunnable implements Runnable{
    @Override
    public void run(){
        Sysmte.out.println(Thread.currentThread().getName());
    }
}
sleep()

執行緒的休眠:

public static void main(String[] args){
    for(int i=0;i<10;i++){
        System.out.println(i);
        Thread.sleep(1000);//每隔1秒輸出一個數
    }
}

執行緒阻塞

執行緒阻塞不光指的是執行緒休眠,執行緒是一條執行路徑,比如說:執行緒在執行代碼時,它的執行路徑有100行,從第一行到第一百行是它的整體執行路徑,這100行中某10行可能是為了讀取某個檔案,這檔案讀取可能耗時1秒鐘,那么這1秒鐘也是阻塞的,停在那讀檔案,后面讀完才會執行,可以把阻塞理解成所有消耗時間的操作,就像上面的讀取檔案,它會使執行緒等待在那個位置,直到讀取完畢,不會往下執行,除非檔案讀完,就像控制臺等待用戶輸入,用戶不輸入,程式就不會繼續往下執行,這就是執行緒阻塞,我們也稱其為耗時操作,

執行緒中斷

一個執行緒是一個獨立的執行路徑,它是否應該結束,應該由其自身決定,執行緒啟動程序中可能會使用N多資源,也涉及到N多需要釋放的資源,那么這時如果由外部直接把執行緒掐死,那么極有可能導致執行緒占用的資源來不及釋放而一直占用,從而產生記憶體垃圾,這個垃圾是你不能回收的垃圾,也有可能占用一些硬體資源,導致硬體資源來不及釋放,其他軟體沒有辦法再去使用,

執行緒中斷不用stop方法,因為此方法是直接把執行緒掐死,我們應該使用interrupt方法,通過該方法給執行緒打上一個標記,在特殊情況下執行緒會檢查iterrupt的狀態,如果檢查到就是報例外,就是告訴執行緒該自殺了,執行緒在捕獲例外陳述句塊里呼叫return方法就會中斷執行緒,

public static void main(String[] args){
    Thread t1 = new Thread(new MyRunnable());
    t1.start();
    for(int i=1;i<=5;i++){
        System.out.println(Thread.currentThread().getName()+":"+i);
        try{
            Thread.sleep(1000);
        } catch(InterruptedException e) {
        	e.printStackTrace();
        }
    }
    //給執行緒t1添加中斷標記
    t1.interrupt();
}
static class MyRunnable implements Runnable{
    @Override
    public void run(){
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
            try{
                Thread.sleep(1000);
            } catch(InterruptedException e) {
                System.out.println("發現了中斷標記,我們這個執行緒自殺");
                return;
            }
        }
    }
}

在這里插入圖片描述

守護執行緒

執行緒:分為守護執行緒和用戶執行緒;

用戶執行緒:當一個行程不包含任何存活的用戶執行緒時,行程結束;

守護執行緒:守護用戶執行緒的,當最后一個用戶執行緒結束時,所有守護執行緒自動死亡,

public static void main(String[] args){
    Thread t1 = new Thread(new MyRunnable());
    t1.setDaemon(true);//設定t1為守護執行緒
    t1.start();
    for(int i=1;i<=5;i++){
        System.out.println(Thread.currentThread().getName()+":"+i);
        try{
            Thread.sleep(1000);
        } catch(InterruptedException e) {
        	e.printStackTrace();
        }
    }
}
static class MyRunnable implements Runnable{
    @Override
    public void run(){
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
            try{
                Thread.sleep(1000);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在這里插入圖片描述

執行緒安全問題

public static void main(String[] args){
    //執行緒不安全
    Runnable run = new Ticket();
    new Thread(run).start();
    new Thread(run).start();
    new Thread(run).start();
}
static class Ticket implements Runnable{
    private int count = 10;
    @Override
    public void run(){
        wile(count>0){
            System.out.println("正在準備賣票");
            try{
                Thread.sleep(1000);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
            count--;
            System.out.println("出票成功,余票:"+count);
        }
    }
}//三個執行緒會有可能會同時進入回圈,同時呼叫count,從而造成count<0的情況發生

在這里插入圖片描述

synchronized(執行緒同步)

執行緒同步有三種方式,三種加鎖的方式,

1、同步代碼塊

格式:synchronized(鎖物件){ }

Java中任何物件都可以作為鎖物件存在,多個執行緒應該搶一把鎖,而不是一個執行緒一把鎖,這樣就不會出現同時操作造成資料混亂的情況了,因為都是排隊執行代碼塊里的代碼,

public static void main(String[] args){
    Runnable run = new Ticket();
    new Thread(run).start();
    new Thread(run).start();
    new Thread(run).start();
}
static class Ticket implements Runnable{
    private int count = 10;
    Object o = new Object();
    @Override
    public void run(){
        //Object o = new Object();//注意:如果鎖宣告在這里,那三個執行緒呼叫run方法都會重新定義一把鎖,那就還是同時執行,不是排隊執行了,
        while(true){
            synchronized(o){//o作為鎖物件,三個執行緒誰搶到了,誰執行代碼塊里的代碼
                if(count>0){
                	System.out.println("正在準備賣票");
            		try{
                		Thread.sleep(1000);
            		} catch(InterruptedException e) {
                		e.printStackTrace();
            		}
            		count--;
            		System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+count);
            	} else {
               		break;
            	}
            }
        }
    }
}

在這里插入圖片描述

2、同步方法

如果不是靜態的(static)的同步方法,它的鎖物件為this;如果是靜態的同步方法,它的鎖物件為類名.class,比如下方的例子中,如果是靜態的,則鎖物件為Ticket.class

public static void main(String[] args){
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    	//new Thread(new Ticket()).start()//這里不是同一把鎖,所以是同時執行(異步),不是排隊執行(同步)了,
}
static class Ticket implements Runnable{
        private int count = 10;
        @Override
        public void run(){
            //synchronized(){  }//如果這里同步代碼塊和同步方法同時用了一把鎖,那么一個執行緒執行同步方法活同步代碼塊時,其他執行緒對同步方法和同步代碼塊都不能執行,就好比商店里的試衣間,大門和試衣間的門用的是同一把鎖,那么只要有一個人(執行緒)在使用其中的一個試衣間,那么其他人連大門都進不去,只能等待里面的人用完試衣間把鎖打開,
            while(true){
                boolean flag = sale();
                if(!flag){
                    break;
                }
            }
        }
        public synchronized boolean sale(){
            if(count>0){
                System.out.println("正在準備賣票");
                try{
                    Thread.sleep(1000);
                } catch(InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+count);
                return true;
            } else {
                return false;
            }
        }
}

在這里插入圖片描述

3、顯示鎖(Lock)

同步代碼塊和同步方法都屬于隱式鎖,

顯示鎖Lock子類ReentrantLock

public static void main(String[] args){
    Runnable run = new Ticket();
    new Thread(run).start();
    new Thread(run).start();
    new Thread(run).start();
}
static class Ticket implements Runnable{
    private int count = 10;
    private Lock l = new ReentrantLock();//顯示鎖
    @Override
    public void run(){
        while(true){
            l.lock();
            if(count>0){
                System.out.println("正在準備賣票");
            	try{
                	Thread.sleep(1000);
            	} catch(InterruptedException e) {
                	e.printStackTrace();
            	}
            	count--;
            	System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+count);
            } else {
               	break;
            }
            l.unlock();
        }
    }
}

在這里插入圖片描述

公平鎖和非公平鎖

公平鎖就是排隊時誰先來,誰就先用這個鎖,

非公平鎖就是排隊時搶著來,誰先搶到誰就用,上述Java執行緒同步的三種方式就是非公平鎖,

在顯示鎖中定義時,建構式的第一個引數設為true就是公平鎖,false就是不公平鎖,例如:

private Lock l = new ReentrantLock(true)//fair引數設為true,就表示公平鎖

執行緒死鎖

兩個執行緒相互等待對方釋放鎖就造成了死鎖,比如某商城有A、B兩個試衣間,客戶甲進入了A試衣間,客戶乙進入了B試衣間,但是客戶甲覺得A試衣間不好用,想換到B試衣間,所以客戶甲在A試衣間中等客戶乙用完B試衣間出來,巧的是客戶已也覺得B試衣間不好用,也想換到A試衣間,所以客戶乙也再等客戶甲用完A試衣間出來,雙方都不知道對方都在等自己用完試衣間出來,而造成的一種相互等待的狀態,就叫做死鎖,

public static void main(String[] args){
    Culprit c = new Culprit();
    Police p = new Police();
    new MyThread(c,p).start();
    c.say(p);
    //在這里主執行緒和MyThread執行緒同時執行,主執行緒拿到了罪犯類里的同步方法鎖,只有主執行緒能呼叫罪犯類里的同步方法,而MyThread執行緒拿到了警察類里的同步方法的鎖,只有MyThread執行緒能呼叫警察類里的同步方法,這樣,主執行緒就需要等待MyThread執行緒釋放所占用的鎖,而MyThread執行緒也同樣需要等待主執行緒釋放所占用的鎖,這樣就造成了兩執行緒相互等待的狀態,從而形成了死鎖,
    //如果想要兩個執行緒不造成死鎖,那么就需要在其中一個執行緒還沒有搶占到鎖時,程式就執行完畢,這樣才不會造成死鎖,
    //避免死鎖的方法就是,你已經呼叫了一個同步方法,就不要再繼續呼叫其他同步方法了,避免造成死鎖,
}
static class MyThread extends Thread{
    private Culprit c;
    private Police p;
    public MyThread(Culprit c,Police p){
        this.c = c;
        this.p = p;
    }
    @Override
    public void run(){
        p.say(c);
    }
}
//罪犯
static class Culprit{
    public synchronized void say(Police p){//說
        System.out.println("罪犯:你放了我,我放了人質");
        p.response();
    }
    public synchronized void response(){//回應
        System.out.println("罪犯被放了,罪犯也放了人質");
    }
}
//警察
static class Police{
    public synchronized void say(Culprit c){
        System.out.println("警察:你放了人質,我放了你");//警察說了話,需要罪犯的回應
        c.response();
    }
    public synchronized void response(){
        System.out.println("警察救到了人質,但是罪犯跑了")
    }
}

出現死鎖的情況:

在這里插入圖片描述

沒有出現死鎖的情況:

在這里插入圖片描述

多執行緒通信問題

Object類里的notify()、notifyAll()、wait()方法,

生產者與消費者

就像廚師和服務員,廚師在做飯的時候,服務員是在休息的,等廚師做好了,服務員被喚醒,而廚師進入休息狀態,

確保生產者在生產時消費者沒有進行消費,

public static void main(String[] args){
    Food f = new Food();
    new Cook(f).start();
    new Waiter(f).start();
}
//廚師
static class Cook extends Thread{
    private Food f;
    public Cook(Food f){
        this.f = f;
    }
    @Override
    public void run(){
        for(int i=0;i<100;i++){
            if(i%2==0){
                f.setNameAndTaste("老干媽小米粥","香辣味");
            } else {
                f.setNameAndTaste("煎餅果子","甜辣味");
            }
        }
    }
}
//服務員
static class Waiter extends Thread{
    private Food f;
    public Waiter(Food f){
        this.f = f;
    }
    @Override
    public void run(){
        for(int i=0;i<100;i++){
            try{
                Thread.sleep(100);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
            f.get();
        }
    }
}
//食物
static class Food{
    private String name;
    private String taste;
    public void setNameAndTaste(String name,String taste){
        this.name = name;
        try{
            Thread.sleep(100);
        } catch(InterruptedException e){
            e.printStackTrace();
        }
        this.taste = taste;
    }
    public void get(){
        System.out.println("服務員端走的菜的名稱是:"+name+",味道:"+taste);
    }
}

在這里插入圖片描述

造成上述錯亂的原因是廚師做食物Food的時候剛給食物賦名字name,就被服務員端走了,而味道taste有可能是上一個物件遺留的,這就是兩個執行緒合作時出現的不協調現象,

而如果把食物的兩個方法定義成同步方法,會造成更加錯亂的現象,有可能,廚師做完了第一頓飯,有可能服務員還沒來得及端,廚師就做完了第二頓飯,那么第一頓飯就沒了,即廚師做飯做快了,或者服務員端菜端快了,

解決方法:廚師干活的時候,服務員歇著;廚師歇著的時候,服務員干活

static class Food{
    private String name;
    private String taste;
    private boolean flag = true;//飯菜是否做好
    public synchronized void setNameAndTaste(String name,String taste){
        if(flag){
            this.name = name;
        	try{
            	Thread.sleep(100);
        	} catch(InterruptedException e){
            	e.printStackTrace();
        	}
        	this.taste = taste;
            flag = false;
            this.notifyAll();//喚醒在當前this下睡著的所有執行緒
            try{
                this.wait();//廚師睡著
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public synchronized void get(){
        if(!flag){
            System.out.println("服務員端走的菜的名稱是:"+name+",味道:"+taste);
            flag = true;
            this.notifyAll();
            try{
                this.wait();
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在這里插入圖片描述

執行緒的六種狀態

執行緒狀態,執行緒可以處于以下狀態之一:

  • NEW
    尚未啟動的執行緒處于此狀態,
  • RUNNABL
    在Java虛擬機中執行的執行緒處于此狀態,
  • BLOCKED
    被阻塞等待監視器鎖定的執行緒處于此狀態,
  • WAITING
    無限期等待另一個執行緒執行特定操作的執行緒處于此狀態,
  • TIMED_WAITING
    正在等待另一個執行緒執行最多指定等待時間的操作的執行緒處于此狀態,
  • TERMINATED
    已退出的執行緒處于此狀態,

執行緒在給定時間點只能處于一種狀態, 這些狀態是虛擬機狀態,不反映任何作業系統執行緒狀態,

在這里插入圖片描述

特殊的創建方法

Interface Callable

有兩種用法:1、和主執行緒一起運行,和執行緒一樣;2、主執行緒等待其完成

Callable和Runnable的區別

介面定義:

public interface Callable<V> {
    V call() throws Exception;
}
public interface Runnable {
    public abstract void run();
}

Callable使用步驟:

//1、撰寫類實作Callable介面,實作call方法
class xxx implements Callable<T> {
    @Override
    public <T> call() throws Exception {
        return T;
    }
}
//2、創建FutureTask物件,并進入第一步撰寫的Callable物件
FutureTask<Integer> future = new FutureTask<>(Callable);
//3、通過thread啟動執行緒
new Thread(future).start();
Runnable與Callable的相同點
  • 都是介面
  • 都可以撰寫多執行緒程式
  • 都采用Thread.start()啟動執行緒
Runnable與Callable的不同點
  • Runnable沒有回傳值;Callable可以回傳執行結果
  • Callable介面的call()允許拋出例外;Runnable的run()不能拋出
public static void main(String[] args){
    Callable<Integer> c = new MyCallable();
    FutureTask<Integer> task = new FutureTask<>(c);
    new Thread(task).start();
    Integer j = task.get();//呼叫get方法會導致主執行緒停在這里,等待MyCallable執行緒執行完畢
    //task.cancel(true);//取消執行緒
    System.out.println("回傳值:"+j);
    for(int i=0;i<10;i++){
        try{
           Thread.sleep(100); 
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    	System.out.println(i);
    }
}
static class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        //Thread.sleep(3000);
        for(int i=0;i<10;i++){
        	try{
           		Thread.sleep(100); 
        	} catch(InterruptedException e) {
           		e.printStackTrace();
        	}
            System.out.println(i);
        }
        return 100;
    }
}

執行緒池概述

執行緒操作流程:創建執行緒 -> 創建任務 -> 執行任務 -> 關閉執行緒

其中最耗費時間的是創建執行緒和關閉執行緒,

執行緒池Executors

如果并發的執行緒數量很多,并且每個執行緒都是執行一個時間很短的任務就結束了,這樣頻繁創建執行緒就會大大降低系統的效率,因為頻繁創建執行緒和銷毀執行緒需要時間,執行緒池就是一個容納多個執行緒的容器,池中的執行緒可以反復使用,省去了頻繁創建執行緒物件的操作,節省了大量的時間和資源,

執行緒池的好處
  • 降低資源的消耗;
  • 提高回應速度;
  • 提高執行緒的可管理性;
執行緒池原理圖

在這里插入圖片描述

Java中的四種執行緒池 .ExecutorService
1、快取執行緒池

特點:長度無限制,

執行流程:

  1. 判斷執行緒池是否存在空閑執行緒
  2. 存在則使用
  3. 不存在,則創建執行緒并放入執行緒池,然后使用
public static void main(String[] args){
    ExecutorService service = Executor.newCachedThreadPool();
    //向執行緒池中加入新的任務
    service.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println("執行緒的名稱:"+Thread.currentThread().getName());
        }
    });
    service.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println("執行緒的名稱:"+Thread.currentThread().getName());
        }
    });
    service.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println("執行緒的名稱:"+Thread.currentThread().getName());
        }
    });
}
2、定長執行緒池

特點:長度是指定的數值

執行流程:

  1. 判斷執行緒池是否存在空閑執行緒
  2. 存在則使用
  3. 不存在空閑執行緒,且執行緒未滿的情況下,則創建執行緒,并放入執行緒池,然后使用
  4. 不存在空閑執行緒,且執行緒已滿的情況下,則等待執行緒池存在空閑執行緒
public static void main(String[] args) {
    ExecutorService service = Executors.newFixedThreadPool(2);
	service.execute(new Runnable() {
    	@Override
    	public void run() {
    		System.out.println("執行緒的名稱:"+Thread.currentThread().getName());
    	}
	});
	service.execute(new Runnable() {
    	@Override
    	public void run() {
    		System.out.println("執行緒的名稱:"+Thread.currentThread().getName());
    	}
	});
}
3、單執行緒執行緒池

特點:效果與定長執行緒池創建時傳入數值1效果一樣,

執行流程:

  1. 判斷執行緒池的那個執行緒是否空閑
  2. 空閑則使用
  3. 不空閑,則等待池中的單個執行緒空閑后使用
public static void main(String[] args){
    ExecutorService service = Executors.newSingleThreadExecutor();
    service.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println("執行緒的名稱:"+Thread.currentThread().getName());
        }
    });
    service.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println("執行緒的名稱:"+Thread.currentThread().getName());
        }
    });
}

4、周期性任務定長執行緒池

執行流程:

  1. 判斷執行緒池是否存在空閑執行緒;
  2. 存在則使用;
  3. 不存在空閑執行緒,且執行緒池未滿的情況下,則創建執行緒,并放入執行緒池,然后使用;
  4. 不存在空閑執行緒,且執行緒池已滿的情況下,則等待執行緒池存在空閑執行緒;

周期性任務執行時:定時執行,當某個時機觸發時,自動執行某個任務

ScheduledExecutorService service = Executors.newScheduledThreadPool(2);

定時執行

引數1. runnable型別的任務

引數2. 時長數字

引數3. 時長數字的單位

service.schedule(new Runnable() {
    @Override
    public void run() {
        System.out.println("倆人相視一笑~嘿嘿嘿");
    }
},5,TimeUnit.SECONDS);

周期執行

引數1. runnable型別的任務

引數2. 時長數字(延遲執行的時長)

引數3. 周期時長(每次執行的間隔時間)

引數4. 時長數字的單位

service.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("倆人相識一笑~嘿嘿嘿");
    }
},5,1,TimeUnit.SECONDS);

Lambda運算式

函式式編程思想

面向物件:創建物件呼叫方法解決問題,

Lambda運算式關注的是物件的方法,

//冗余的Runnable代碼
public static void main(String[] args) {
    MyRunnable r = new MyRunnable();
    Thread t = new Thread(r);
    t.start();
}
public static class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("鋤禾日當午");
    }
}
//改善之后的Runnable代碼
public static void main(String[] args) {
    Thread t = new Thread(new Runnable() {
        @Override
    	public void run() {
        	System.out.println("鋤禾日當午");
    	}
    });
    t.start();
}
//使用Lambda運算式改善Runnable代碼
public static void main(String[] args) {
    Thread t = new Thread(() -> System.out.println("鋤禾日當午"));//效果和上述代碼一致
    //Thread t = new Thread(() -> {System.out.println("鋤禾日當午");});
    t.start();
}

//自定義介面測驗
public static void main(String[] args) {
    /*print(new MyMath() {
        @Override
        public int sum(int x,int y) {
            return x+y;
        }
    },100,200);*/
    print((int x,int y) -> {
        return x+y;
    },100,200);
}
public static void print(MyMath m,int x,int y){
    int num = m.sum(x,y);
    System.out.println(num);
}
static interface MyMath {
    int sum(int x,int y);
}

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

標籤:其他

上一篇:人工智能在網路安全中的攻擊和防御

下一篇:必過SafetyNet!以MIUI開發版系統為例詳解Android設備通過SafetyNet校驗方法

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

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more