java review

才下眉头3發表於2024-12-09

一、多型

  • 向上轉型
    • FU fu = new Zi();
    • 可以呼叫子類方法,不能呼叫子類特有方法 (成員方法)
    • 成員變數,看等號左邊的是誰,呼叫誰裡面的成員變數

二、內部類

1.什麼時候使用內部類:

​ 當一個事務的內部,還有一個部分需要定義完整的結構去描述,而這個內部的完整結構又只為外部事物提供服務。那麼整個內部的完整結構最好使用內部類

2.分類:

成員內部類(靜態、非靜態)

區域性內部類

匿名內部類

1.靜態內部類

1.格式:直接在定義內部類的時候加上static關鍵字
	public class A {
		static class B {
		}
	}
2.注意:
	a.內部類可以定義屬性,方法,構造等
	b.靜態內部類可以用final或者abstract修飾 
	    被final 修飾後不能被繼承
	    被abstract 修飾後不能new
	c.靜態內部類不能呼叫外部的非靜態成員
	d.內部類還可以被四種許可權修飾符修飾
	e.呼叫靜態內部類成員
		外部類.內部類 物件名 = new 外部類.內部類();

2.非靜態內部類

1.格式:
	public class A {
		 class B {
		}
	}
2.注意:
	a.內部類可以定義屬性,方法,構造等
	b.靜態內部類可以用final或者abstract修飾 
	    被final 修飾後不能被繼承
	    被abstract 修飾後不能new
	c.靜態內部類不能呼叫外部的非靜態成員
	d.內部類還可以被四種許可權修飾符修飾
	e.呼叫靜態內部類成員
		外部類.內部類 物件名 = new 外部類().new 內部類();

外部的成員變數和內部類的成員變數以及內部類的區域性變數重名時怎麼辦?

public class Person {
 String name = "楊晨旭";
 class Heart{
     String name = "趙國羽";
     public void display(String name){
         System.out.println(name);//內部類的區域性變數
         System.out.println(this.name); //內部類的成員變數
         System.out.println(Person.this.name); //外部類的成員變數
     }
 }
}

3.區域性內部類

1.可以定義在方法中,程式碼塊中,構造中

public class Person {
 public void eat(){
     class Heart{
         public void jump(){
             System.out.println("心臟怦怦跳");
         }
     }
     new Heart().jump();
 }
}

public class Test01 {
 public static void main(String[] args) {
     Person person = new Person();
     person.eat();
 }
}

3.1區域性內部類實際操作

3.1.1介面型別作為方法引數傳遞和返回值

public interface Usb {
    abstract void open();
}

public class Compute implements Usb{
    @Override
    public void open() {
        System.out.println("compute is openning");
    }
}

public class Test01 {
    public static void main(String[] args) {
        Compute compute = new Compute();
        method(compute);

        Usb usb = method01();
        usb.open();
    }

    public static void method(Usb usb) {
        usb.open();
    }
    public static Usb method01(){
        return new Compute();
    }
}

3.1.2抽象類作為方法引數傳遞和返回值

1.抽象類作為方法引數傳遞,傳遞的是其子類物件

2.抽象類作為方法返回值型別返回時,實際返回的是其子類物件

3.1.3普通類做方法引數和返回值

普通類作為方法引數傳遞,傳遞的是物件

普通類作為方法返回值返回,返回的是物件

3.1.4區域性內部類實際操作

public interface Usb {
     void open();
}

public class Test01 {
    public static void main(String[] args) {
        Usb usb = method01();
        usb.open();
    }
    public static Usb method01(){
        //區域性內部類
        class Compute implements Usb{
            @Override
            public void open() {
                System.out.println("電腦開啟了");
            }
        }
        return new Compute();
    }
}

4.匿名內部類

可以理解為沒有顯式的宣告出類名的內部類

格式:

​ new 介面/抽象類(){

​ 重寫方法

​ }.重寫的方法();

類名 物件名 = new 介面/抽象類(){

​ 重寫方法

​ }

物件名.重寫的方法

public interface Usb {
     void open();
}

public class Test01 {
    public static void main(String[] args) {
        new Usb(){
            @Override
            public void open() {
                System.out.println("xaioguo");
            }
        }.open();
    }
}

Object中的clone方法

1.作用:複製一個屬性值一樣的新物件

2.使用:

​ 需要被克隆的物件實現Cloneable

​ 重寫clone方法

三、經典介面

1.java.lang.Comparable

  • 哪個類的物件要比較大小,哪個類就實現java.lang.Comparable介面,並重寫方法
    • 方法體就是你要如何比較當前物件和指定的另一個物件的大小
  • 物件比較大小時,透過物件呼叫compare To方法,根據方法的返回值決定誰大誰小
    • this物件(呼叫compareTo方法的物件) 減 指定物件 (傳入compareTo()的引數物件)大於0,返回正整數
    • this物件(呼叫compareTo方法的物件) 減 指定物件 (傳入compareTo()的引數物件)小於0,返回負整數
    • this物件(呼叫compareTo方法的物件) 減 指定物件 (傳入compareTo()的引數物件)等於0,返回零

2.java.util.Comparator

(1)如果一個類,沒有實現Comparable介面,而這個類又不方便修改。(例如一些第三方的類,只有class類,沒有原始檔)

(2)如果一個類,實現了Comparable介面,也指定了兩個物件的比較大小的規則,但是不小按照它預定義的方法比較大小,但是又不可以隨意修改,因為會影響其他地方的使用。

package java.util
public interface Comparator{
    int compare(Object o1,Object o2);
}
  • 編寫一個類,比較器型別,實現java.util.Comparator介面,並重寫方法
    • 方法體就是你要如何指定的兩個物件的大小
  • 比較大小時,透過比較器型別的物件呼叫compare()方法,將要比較大小的兩個物件作為compare方法的實參傳入

四、多執行緒

1.會使用多執行緒方法,主要是start方法

2.會使用繼承Thread的方式建立多執行緒

3.會使用Runnable介面的方式實現多執行緒

4.會使用同步程式碼塊,解決執行緒不安全問題

5.會使用同步方法,解決執行緒不安全問題

多執行緒的基本瞭解

1.多執行緒_執行緒和程序

程序:在記憶體中執行的應用程式
執行緒:是程序中的最小執行單元
執行緒作用:負責當前程序中程式的執行,一個程序中至少有一個執行緒,一個進程序還可以有多個執行緒,這樣的應用程式就稱之為多執行緒程式。
簡單理解: 一個功能,需要一個執行緒

使用場景:軟體中的耗時操作-->複製大檔案,載入大量的資源

​ 所有的聊天軟體 、所有的後臺伺服器。

一個執行緒可以幹一件事,同時做多件事,提高CPU利用率

2.併發和並行

並行:在同一個時刻,有多個執行在多個CPU上同時執行

併發:在同一個時刻,有多個指令在單個CPU上(交替)執行。

1.之前cpu是單核,但是在執行多個程式的時候好像是在同時執行,原因是CPU在多個執行緒之間做高速切換

2.現在cpu多核多執行緒,例如2核4執行緒,cpu可以同時執行4個執行緒,此時不同切換,但是如果多了,cpu就要i耳環了,所以現在cpu在執行程式的時候併發和並行同時存在。

3.cpu排程

1.分時排程:指的是讓所有的執行緒輪流獲取cpu使用權,並且平均分配每個執行緒佔用cpu的時間片

2.搶佔式排程:多個執行緒輪流搶佔cpu的使用權,哪個執行緒先搶到了,哪個執行緒線執行,一般都是優先順序高的搶到cpu使用權的機率大,java程式就是搶佔式呼叫的。

4.主執行緒

cpu和記憶體之間開闢的專門為main方法服務的執行緒,稱為主執行緒

建立執行緒的方式

第一種方式 extends Thread

1.定義一個類,繼承Thread類

2.重寫run方法,在run方法中設定執行緒任務(所謂的執行緒任務指的是此執行緒要乾的具體的事兒,具體執行的程式碼)

3.建立自定義執行緒類的物件

4.呼叫Thread中的start方法,開啟執行緒,jvm自動呼叫run方法

1.多執行緒在記憶體中的執行原理

開啟一個執行緒,會開啟一個棧空間去執行對應的執行緒程式碼,

注意: 同一個執行緒物件不能連續呼叫多次start方法。

2.Tread類中的方法

void start() -->開啟執行緒,jvm自動呼叫run方法

void run() -->設定執行緒任務,這個run方法是Thread重寫的介面Runnable中的run方法

String getName() --> 獲取執行緒名字

void setName(String name) --> 給執行緒設定名字

static Thread currentThread() -->獲取正在執行的執行緒物件(該方法在哪個執行緒物件中使用,獲取的就是哪個執行緒物件)

static void sleep(long millis) --> 執行緒睡眠,超時後會自動醒來,傳遞的是毫秒值。

3.Thread中的其他方法

void setPriority(int newPriority) -->設定執行緒優先順序,優先順序越高,搶到CPU使用權的機率越大,但不是每次都先搶到
int getPriority()  -->獲取執行緒優先順序
void setDaemon(boolean on) -->設定為守護執行緒,當非守護執行緒執行完畢,守護執行緒就要結束
static void yield() ——>禮讓執行緒,讓當前執行緒讓出CPU使用權
void join()         -->插入執行緒、插隊執行緒

守護執行緒

package d_thread;

public class MyThread extends Thread{
    public void run(){
        for (int i = 0; i < 10; i++) {
            System.out.println(getName() + "...執行了" + i);
        }
    }
}

package d_thread;

public class MyThread2 extends Thread{
    public void run(){
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "...執行了" + i);
        }
    }
}
package d_thread;

public class Test01 extends Thread{
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.setName("楊旭");
        MyThread2 t2 = new MyThread2();
        t2.setName("馬宏");
        t2.setDaemon(true);
        t1.start();
        t2.start();
    }
}
--
馬宏...執行了0
馬宏...執行了1
楊旭...執行了0
楊旭...執行了1
楊旭...執行了2
馬宏...執行了2
馬宏...執行了3
楊旭...執行了3
楊旭...執行了4
楊旭...執行了5
楊旭...執行了6
楊旭...執行了7
楊旭...執行了8
馬宏...執行了4
楊旭...執行了9
馬宏...執行了5
馬宏...執行了6
馬宏...執行了7
馬宏...執行了8
馬宏...執行了9
馬宏...執行了10
馬宏...執行了11
馬宏...執行了12
---

禮讓執行緒

場景:如果兩個執行緒一起執行,可能會執行一會執行緒A,在執行一會執行緒B,或者可能執行緒A執行完畢了,執行緒B再執行,那麼我們能不能讓兩個執行緒儘可能的平衡一點 —>儘量讓兩個執行緒交替執行。

插入執行緒

public class Test01 extends Thread{
    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread();
        t1.setName("楊旭");

        t1.start();
        t1.join();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "...執行了" + i);

        }
    }
}

public class MyThread extends Thread{
    public void run(){
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "...執行了" + i);
        }
    }
}

第二種方式

1.建立類,實現Runnable介面

2.重寫run方法,設定執行緒任務

3.利用Thread類的構造方法: Thread(Runnable target),建立Thread物件(執行緒物件),將自定義的類當引數傳遞到Thread構造中 --> 這一步是讓我們自己定義的類成為一個真正的執行緒類物件。

4.呼叫Thread中start方法,開啟執行緒,jvm自動呼叫run方法。

兩種實現多執行緒的方式區別

1.繼承Thread:繼承只支援單繼承,有繼承的侷限性

2.實現Runnable:沒有繼承的侷限性,MyThread extends Fu implements Runnable

第三種方式_匿名內部類建立多執行緒

嚴格意義上來說:匿名內部類方式部署於建立多執行緒方式其中之一,因為匿名內部類形式建立在實現Runnable介面的基礎上完成的

匿名內部類 :
	1.new 介面/抽象類(){
		重寫方法
	}.重寫的方法();
	2.介面名/類名 物件名 =new 介面/抽象類(){
		重寫方法
	}
	物件名.重寫的方法	
	

public class Test02 {
    public static void main(String[] args) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "...執行了" + i + "次");
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "...執行了" + i + "次");
                }
            }
        },"yangxu").start();
    }

執行緒安全問題

1.執行緒安全問題--> 執行緒不安全的程式碼

原因: Cpu在多個執行緒之間做高速切換導致的

public class MyTicket implements Runnable{
    //定義100張票
    int ticket =100;
    @Override
    public void run() {
      while (true){
          if (ticket > 0){
              System.out.println(Thread.currentThread().getName() + "買了第" + ticket + "張票");
              ticket --;
          }
      }
    }
}

public class Test01 {
    public static void main(String[] args) {
        MyTicket myTicket = new MyTicket();
        Thread t1 = new Thread(myTicket, "楊旭");
        Thread t2 = new Thread(myTicket, "馬洪");
        Thread t3 = new Thread(myTicket, "趙桑");
        t1.start();
        t2.start();
        t3.start();
    }
}

2.解決執行緒安全問題的第一種方式(使用同步程式碼塊)

1.格式: 
  synchronized(任意物件){
  		執行緒可能出現不安全的程式碼
  }
2. 任意物件: 就是我們的鎖物件
3. 執行: 
 	一個執行緒拿到鎖之後會進入到同步程式碼塊中執行,在此期間,其他執行緒拿不到鎖,就進不去同步程式碼塊,需要在同步程式碼塊外面等待排隊,
 	需要等著執行的執行緒執行完畢,出了同步程式碼塊,相當於釋放鎖,等待的執行緒才能搶到鎖,才能進入到同步程式碼塊中執行。
 
public class MyTicket implements Runnable{
    Object obj = new Object();
    //定義100張票
    int ticket =100;
    @Override
    public void run() {

        while (true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
                synchronized (obj){
                    if (ticket > 0){
                        System.out.println(Thread.currentThread().getName() + "買了第" + ticket + "張票");
                        ticket --;
                    }
                }

            }
        }


}


public class Test01 {
    public static void main(String[] args) {
        MyTicket myTicket = new MyTicket();
        Thread t1 = new Thread(myTicket, "楊旭");
        Thread t2 = new Thread(myTicket, "馬洪");
        Thread t3 = new Thread(myTicket, "趙桑");
        t1.start();
        t2.start();
        t3.start();
    }
}

3.解決執行緒安全問題的第二種方式:同步方法

3.1普通同步法:非靜態

1. 格式:
	修飾符 synchronized 返回值型別 方法名(引數){
		方法體
		return 結果 
	}
2. 預設鎖是this
    
    public class MyTicket implements Runnable {
    //定義100張票
    int ticket = 100;

    @Override
    public void run() {

        while (true) {
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
//            method01();
            method02();
        }
    }

    //    public synchronized void method01() {
//        if (ticket > 0) {
//            System.out.println(Thread.currentThread().getName() + "買了第" + ticket + "張票");
//            ticket--;
//        }
//    }
    public  void method02() {
        synchronized (this){
            System.out.println(this+ "......");
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "買了第" + ticket + "張票");
                ticket--;
            }
        }

    }
}
public class Test01 {
    public static void main(String[] args) {
        MyTicket myTicket = new MyTicket();
        System.out.println(myTicket);
        Thread t1 = new Thread(myTicket, "楊旭");
        Thread t2 = new Thread(myTicket, "馬洪");
        Thread t3 = new Thread(myTicket, "趙桑");
        t1.start();
        t2.start();
        t3.start();
    }
}

3.2靜態同步方法

1. 格式:
	修飾符 static synchronized 返回值型別 方法名(引數){
		方法體
		return 結果 
	}
2.預設鎖  class物件
    
    public class MyTicket implements Runnable {
    //定義100張票
    static int ticket = 100;

    @Override
    public void run() {

        while (true) {
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
//            method01();
            method02();
        }
    }

//        public static synchronized void method01() {
//        if (ticket > 0) {
//            System.out.println(Thread.currentThread().getName() + "買了第" + ticket + "張票");
//            ticket--;
//        }
//    }
    public  void method02() {
        synchronized (MyTicket.class){

            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "買了第" + ticket + "張票");
                ticket--;
            }
        }

    }
}
public class Test01 {
    public static void main(String[] args) {
        MyTicket myTicket = new MyTicket();
        System.out.println(myTicket);
        Thread t1 = new Thread(myTicket, "楊旭");
        Thread t2 = new Thread(myTicket, "馬洪");
        Thread t3 = new Thread(myTicket, "趙桑");
        t1.start();
        t2.start();
        t3.start();
    }
}

死鎖

1.死鎖介紹(鎖巢狀就有可能產生死鎖)

指的是兩個或兩個以上的執行緒在執行的過程中由於競爭同步鎖而產生的一種阻塞現象;

如果沒有外力的作用,它們將無法繼續執行下去,這種情況稱之為死鎖。

執行緒1持有鎖1,執行緒2持有鎖2,執行緒1必須再拿到鎖2才能繼續執行,

執行緒2必須再拿到鎖1才能繼續執行,此時兩個執行緒處於互相等待的狀態,

在程式中的死鎖將出現在同步程式碼塊的巢狀中

public class LockA {
    public static LockA lockA = new LockA();
}
public class LockB {
    public static LockB lockB = new LockB();
}
public class DieLock implements Runnable {
    private Boolean flag;

    public DieLock(Boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if (flag) {
            synchronized (LockA.lockA) {
                System.out.println("if ....lockA");
                synchronized (LockB.lockB) {
                    System.out.println("if ...lockB");
                }
            }
        } else {
            synchronized (LockB.lockB) {
                System.out.println("else ....lockB");
                synchronized (LockA.lockA) {
                    System.out.println("else ...lockA");
                }
            }
        }

    }
}
public class Test01 {
    public static void main(String[] args) {
        DieLock dieLock1 = new DieLock(true);
        DieLock dieLock2 = new DieLock(false);

        new Thread(dieLock1).start();
        new Thread(dieLock2).start();
    }
}
//也有可能不出現死鎖
 if ....lockA
 if ...lockB
 else ....lockB
 else ...lockA

多執行緒_等待喚醒案例

package wait_notify;

public class BaoziPu {
    private int count;
    private boolean flag;

    public BaoziPu() {
    }

    public void getCount() {
        System.out.println("消費了"+ "第"+count + "包子");
    }

    public void setCount() {
        count++;
        System.out.println("生產了.....第" + count+"包子");
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public BaoziPu(int count, boolean flag) {
        this.count = count;
        this.flag = flag;
    }
}


package wait_notify;

public class Product implements Runnable{
  private  BaoziPu baoziPu;

    public Product(BaoziPu baoziPu) {
        this.baoziPu = baoziPu;
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            synchronized (baoziPu){
                if(baoziPu.isFlag() == true){
                    try {
                        baoziPu.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                baoziPu.setCount();
                baoziPu.setFlag(true);
                baoziPu.notify();
            }
        }
    }
}

package wait_notify;

public class Comsumer implements Runnable{
    private  BaoziPu baoziPu;

    public Comsumer(BaoziPu baoziPu) {
        this.baoziPu = baoziPu;
    }
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            synchronized (baoziPu){
                if(baoziPu.isFlag() == false){
                    try {
                        baoziPu.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                baoziPu.getCount();
                baoziPu.setFlag(false);
                baoziPu.notify();
            }
        }
    }
}

public class Test {
    public static void main(String[] args) {
        BaoziPu baoziPu = new BaoziPu();

        Product product = new Product(baoziPu);
        Comsumer comsumer = new Comsumer(baoziPu);

        Thread t1 = new Thread(product);
        Thread t2 = new Thread(comsumer);

        t1.start();
        t2.start();
    }
}

程式碼改進

public synchronized void getCount() {
        while (true) {
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            if (this.isFlag() == false) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("消費了" + "第" + count + "包子");

            this.setFlag(false);
            this.notify();

        }

    }

    public synchronized void setCount() {
        while (true) {
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            if (this.isFlag() == true) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            count++;
            System.out.println("生產了.....第" + count + "包子");
            this.setFlag(true);
            this.notify();

        }
    }

    public void run() {
      baoziPu.setCount();
    }

    public void run() {
        baoziPu.getCount();
    }

多等待,多喚醒

while 和notifyAll() 搭配使用

        new Thread(product).start();
        new Thread(product).start();
        new Thread(product).start();

        new Thread(comsumer).start();
        new Thread(comsumer).start();
        new Thread(comsumer).start();

public synchronized void getCount() {
        while (true) {
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            while (this.isFlag() == false) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("消費了" + "第" + count + "包子");

            this.setFlag(false);
            this.notifyAll();

        }

    }

    public synchronized void setCount() {
        while (true) {
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            while (this.isFlag() == true) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            count++;
            System.out.println("生產了.....第" + count + "包子");
            this.setFlag(true);
            this.notifyAll();

        }
    }

多執行緒_Lock鎖

1.Lock物件的介紹和使用

1.概述: Lock物件的介紹和基本使用
2.實現類: ReentrantLock
3.方法: 
    lock() 獲取鎖
    unlock() 釋放鎖

解決執行緒不安全

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyTicket implements Runnable {
    Lock lock = new ReentrantLock();
    //定義100張票
    int ticket = 100;

    @Override
    public void run() {

        while (true) {
            try {
                Thread.sleep(100L);
                lock.lock();
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "買了第" + ticket + "張票");
                    ticket--;
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }
}

        MyTicket myTicket = new MyTicket();
        Thread t1 = new Thread(myTicket, "楊旭");
        Thread t2 = new Thread(myTicket, "馬洪");
        Thread t3 = new Thread(myTicket, "趙桑");
        t1.start();
        t2.start();
        t3.start();

synchronized:不管是同步程式碼塊還是同步方法,都需要在結束一對{}之後,釋放物件

Lock:是透過兩個方法控制需要被同步的程式碼,更靈活。

Callable介面(實現多執行緒的第三種方式)

1.概述:Callable是一個介面,類似於Runnable

2.方法:

V call() -> 設定執行緒任務的,類似於run方法

3.call 方法和run方法的區別:

​ a.相同點:都是設定執行緒任務的

​ b.不同點:call方法有返回值,有異常可以throws

​ run方法沒有返回值,有異常不可以throws

4.

​ a. 泛型

​ b. 泛型:用於指定我們操作什麼型別的資料,<>中只能寫引用資料型別,如果泛型不寫預設是Object型別資料

​ c.實現Callable介面時,指定泛型是什麼型別的,重寫的call方法返回值就是什麼型別的。

5.獲取call方法的返回值:FuntureTask

​ a.FuntureTask 實現了一個介面 Future

​ b.FuntureTask中有一個方法:

​ V get() 獲取call方法的返回值

import java.util.concurrent.Callable;

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "小liu";
    }
}


import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Test01 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable myCallable = new MyCallable();
        /*
        FutureTask(Callable<V> callable)
         */
        FutureTask<String> myFutureTask = new FutureTask<>(myCallable);

        Thread t1 = new Thread(myFutureTask);
        t1.start();
        System.out.println(myFutureTask.get());
    }
}

執行緒池

1.問題:之前來一個執行緒任務,就需要建立一個執行緒物件去執行,用完還要銷燬執行緒物件,如果執行緒任務多了,就需要頻繁建立執行緒物件,銷燬執行緒物件,耗費資源,執行緒物件能不能迴圈使用,用的時候直接拿,用完還回來。

1.如何建立執行緒池物件: 工具類 —> Executors

2.獲取執行緒池物件:Executors中的靜態方法:

static ExecutorService newFixedThreadPool(int nThreads)

​ a.引數:指定執行緒池中最多建立的執行緒物件條數

​ b.返回值ExecutorService 是執行緒池,用來管理執行緒物件

3.執行執行緒任務:ExecutorService 中的方法

​ Future<?> submit(Runnable task) 提交一個Runnable任務用於執行

​ Future<?> submit(Callable task) 提交一個Callable任務用於執行

4.submit方法的返回值:Future介面

​ 用於接收run方法或者call方法返回值的,但是run方法沒有返回值,所以可以不用Future接收,執行call方法需要用Future接收

​ Future中有一個方法: V get() 用於獲取call方法返回值

5.ExecutorService 中的 方法

​ void shutdown() 啟動有序關閉,其中先前提交的任務將被執行,但不會接收任何新任務

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "執行了");
    }
}
public class Test {
    public static void main(String[] args) {

        ExecutorService es = Executors.newFixedThreadPool(2);

        es.submit(new MyRunnable());
        es.submit(new MyRunnable());
        es.submit(new MyRunnable());
        es.shutdown();
    }
}

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return 1;
    }
}

public class Test2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Integer> future = es.submit(new MyCallable());
        System.out.println(future.get());
        es.shutdown();
    }
}

定時器_Timer

1.概述:定時器

2.構造:

Timer()

3.方法:

​ void schedule(TimerTask, Date firstTime,long period)

​ task: 抽象類,是Runnable的一個實現類

​ firstTime:從什麼時間開始執行

​ period: 每個多長時間執行一次,設定的是毫秒值。週期

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Demo01Timer {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("金蓮對楊旭說,旭哥該起床了");
            }
        },new Date(),2000L);
    }
}

相關文章