1. 程式人生 > 其它 >java基礎複習05

java基礎複習05

java基礎複習

面對物件

4.1、Debug追蹤

Debug除錯程式:

  • 可以讓程式碼逐行執行,檢視程式碼執行的過程,除錯程式中出現的bug

使用方式:

  • 在行號的右邊,滑鼠左鍵單擊,新增斷點(每個方法的第一行,哪裡有bug新增到哪裡)右鍵,選擇Debug執行程式
  • 程式就會停留在新增的第一個斷點處

執行程式:

  • f8: 逐行執行程式

  • f7: 進入到方法中

  • shift+f8: 跳出方法

  • f9: 跳到下一個斷點,如果沒有下一個斷點,那麼就結束程式

  • ctrl+f2:退出debug模式,停止程式

  • Console:切換到控制檯

4.2、異常

異常: 指的是程式在執行過程中,出現的非正常的情況,最終會導致JVM的非正常停止。

在 java等面向物件的程式語言中,異常本身是一個類,產生異常就是建立異常物件並丟擲了一個異常物件。Java處理異常的方式是中斷處理。

throw關鍵字作用:

  • 可以使用throw關鍵字在指定的方法中丟擲指定的異常

使用格式:

if(判斷語句){
    throw new xxException(“異常產生的原因"");
}

注意:

  • throw關鍵字必須寫在方法的內部

  • throw關鍵字後邊new的物件必須是Exception或者Exception的子類物件

  • throwv關鍵字丟擲指定的異常物件,我們就必須處理這個異常物件

  • throw關鍵字後邊建立的是RuntimeException或者是RuntimeException的子類物件,我們可以不處理,預設交給JW處理(列印異常物件,中斷程式)

  • throw關鍵字後邊建立的是編譯異常(寫程式碼的時候報錯),我們就必須處理這個異常,要麼throws,要麼try...catch

throws關鍵字

  • 異常處理的第一種方式,交給別人處理

作用:

  • 當方法內部丟擲異常物件的時候,那麼我們就必須處理這個異常物件

  • 可以使用throws關鍵字處理異常物件,會把異常物件宣告批出給方法的呼叫者處理(自己不處理,給別人處理),最終交給JWw處理-->中斷處理

使用格式:在方法宣告時使用

修飾符    返回值型別   方法名(引數列表)    throws AAAExcepiton,BBBExcepiton. . .{
    
}

注意:

  • throws關鍵字必須寫在方法宣告處

  • throws關鍵字後邊宣告的異常必須是Exception或者是Exception的子類

  • 方法內部如果丟擲了多個異常物件,那麼throws後邊必須也宣告多個異常

    • 如果丟擲的多個異常物件有子父類關係,那麼直接宣告父類異常即可
  • 呼叫了一個宣告丟擲異常的方法,我們就必須的處理宣告的異常

    • 要麼繼續使用throws宣告丟擲,交給方法的呼叫者處理,最終交給JVM要麼try...catch自己處理異常

try catch

格式:

try{
    可能產生異常的程式碼
}catch(定義一個異常的變數,用來接收try中丟擲的異常物件){
    異常的處理邏輯,異常物件之後,怎麼處理異常物件
        一般在工作中,會把異常的資訊記錄到一個日誌中
}
catch(異常類名變數名){}

注意:

  • try中可能繪丟擲多個異常物件,那麼就可以使用多個catch來處理這些異常物件

  • 如果try中產生了異常,那麼就會執行catch中的異常處理邏輯,執行完畢catch中的處理邏輯,繼續執行try...catch之後的程式碼如果try中沒有產生異常,那麼就不會執行catch中異常的處理邏輯,執行完try中的程式碼,繼續執行try. ..catch之後的程式碼

Finally程式碼塊

格式:

try{
    可能產生異常的程式碼
}catch(定義一個異常的變數,用來接收try中丟擲的異常物件){
    異常的處理邏輯,異常物件之後,怎麼處理異常物件
        一般在工作中,會把異常的資訊記錄到一個日誌中
}
catch(異常類名變數名){
    
}finally{
    無論是否出現異常都會執行
}

注意:

  • finally 不能單獨使用,必須和try—起使用

  • finally 一般用於資源釋放(資源回收),無論程式是否出現異常,最後都要資源釋放(IO)

  • 如果finally有return語句,永遠返回finally中的結果,應該避免該情況。

4.3、多執行緒

併發:指兩個或多個事件在同一個時問段內發生。(交替執行)

並行:指兩個或多個事件在同一時刻發生(同時發生).(同時執行)

程序:

執行緒︰執行緒是程序中的一個執行單元,負責當前程序中程式的執行,一個程序中至少有一個執行緒。一個程序中是可以有多個執行緒的,這個應用程式也可以稱之為多執行緒程式。(簡而言之:一個程式執行後至少有一個程序,—個程序中可以包含多個執行緒)

執行緒排程

  • 分時排程:

    • 所有執行緒輪流使用CPU的使用權,平均分配每個執行緒佔用CPU的時間。
  • 搶佔式排程:

    • 優先讓優先順序高的執行緒使用CPU,如果執行緒的優先順序相同,那麼會隨機選擇一個(執行緒隨機性),Java使用的為搶佔式排程。

主執行緒:執行主(main)方法的執行緒

單執行緒程式: java程式中只有一個執行緒執行從main方法開始,從上到下依次執行

多執行緒程式

建立多執行緒程式的第一種方式:建立Thread類的子類

java.lang. Thread類:是描述執行緒的類,我們想要實現多執行緒程式,就必須繼承Thread類

實現步驟:

  • 建立一個Thread類的子類

  • 在Thread類的子類中重寫Thread類中的run方法,設定執行緒任務(開啟執行緒要做什麼?)

  • 建立Thread類的子類物件

  • 呼叫Thread類中的方法start方法,開啟新的執行緒,執行run方法

    • void start()使該執行緒開始執行;Java虛擬機器呼叫該執行緒的run方法。
    • 結果是兩個執行緒併發地執行;當前執行緒(main執行緒)和另一個執行緒(執行其 run方法)。
    • 多次啟動一個執行緒是非法的。特別是當執行緒已經結束執行後,不能再重新啟動。
public class MyThread extends Thread{  //1.建立一個Thread類的子類
    @Override
    public void run() {     //2.在Thread類的子類中重寫Thread類中的run方法,設定執行緒任務(開啟執行緒要做什麼?)
        for (int i = 0; i < 20; i++) {
            System.out.println("run:"+i);
        }
    }
}
public class DemoThread {
    public static void main(String[] args) {
        MyThread mt = new MyThread();//3.建立Thread類的子類物件
        mt.start();//4.呼叫Thread類中的方法start方法,開啟新的執行緒,執行run方法
        for (int i = 0; i < 20; i++) {
            System.out.println("main:"+i);
        }
    }
}

建立多執行緒程式的第二種方式:實現Runnable介面 java.Lang . Runnable

實現步驟:

1、建立一個Runnable介面的實現類

2、在實現類中重寫Runnable介面的run方法,設定執行緒任務

3、建立一個Runnable介面的實現類物件

4、建立Thread類物件,構造方法中傳遞Runnable介面的實現類物件

5、呼叫Thread類中的start方法,開啟新的執行緒執行run方法

public class RunnableImpl implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"--->"+i);
        }
    }
}
public class DemoRunnable {
    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"--->"+i);
        }
        RunnableImpl ra = new RunnableImpl();
        Thread th = new Thread(ra);
        th.start();
    }
}

Thread常用方法

public static void sleep(Long millis):使當前正在執行的執行緒以指定的毫秒數暫停〈暫時停止執行)。

public class DemoThread01 {
    public static void main(String[] args) {
        for (int i = 0; i <20 ; i++) {///模擬秒錶
            System.out.println(i);
            try {
                Thread.sleep(1000);//使用Thread類的sleep方法讓程式睡眠1秒鐘
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

匿名內部類方式實現執行緒的建立

匿名內部類作用:簡化程式碼

  • 把子類繼承父類,重寫父類的方法,建立子類物件合一步完成
    把實現類實現類介面,重寫介面中的方法,建立實現類物件合成一步完成

匿名內部類的最終產物:子類/實現類物件,而這個類沒有名字

格式:

new 父類/介面(){
    重複父類介面中的方法
};
public class Demo01 {
    public static void main(String[] args) {
         new Thread() {
             @Override
             public void run() {
                 for (int i = 0; i < 20; i++) {
                     System.out.println(Thread.currentThread().getName()+"+"+i);
                 }
             }
         }.start();
    }
}
public class Demo02 {
    public static void main(String[] args) {//用介面的方式
        Runnable r = new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+"+程式設計師");
                }
            }
        };
        new Thread(r).start();
    }
}

4.4、執行緒安全

多執行緒在用到相同資源時會產生安全問題

解決方法

  • 同步程式碼塊。

  • 同步方法。

  • 鎖機制。

同步程式碼塊:synchronized關鍵字可以用於方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。

格式:

synchronized(同步鎖){
    //需要操作的程式碼
}

注意:

  • 通過程式碼塊中的鎖物件,可以使用任意的物件

  • 但是必須保證多個執行緒使用的鎖物件是同一個

  • 鎖物件作用:

    • 把同步程式碼塊鎖住,只讓一個執行緒在同步程式碼塊中執行
public class RunnableImpl implements Runnable{
    private int ticket = 100;
    Object object = new Object();
    @Override
    public void run() {
        while (true) {
            synchronized (object) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "--->正在賣第:" + ticket + "張票");
                    ticket--;
                }
            }
        }
    }
}
public class DemoMain {
    public static void main(String[] args) {
        RunnableImpl runnable = new RunnableImpl();

        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        Thread t3 = new Thread(runnable);
        t1.start();
        t2.start();
        t3.start();
    }
}

同步方法

  • 把訪問了共享資料的程式碼抽取出來,放到一個方法中

  • 在方法上新增synchronized修飾符

格式:

修飾符  synchronized   返回值型別  方法名(引數列表){
    可能會出現執行緒安全問題的程式碼(訪問了共享資料的程式碼)
}
public class RunnableImpl implements Runnable {
    private int ticket = 100;

    @Override
    public void run() {
        while (true) {
            payTicket();
        }
    }

    public synchronized void payTicket() {
        if (ticket > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "--->正在賣第:" + ticket + "張票");
            ticket--;
        }
    }
}

鎖機制

使用Lock鎖 java.util.concurrent.tocks.Lock介面

Lock實現提供了比使用synchronized 方法和語句可獲得的更廣泛的鎖定操作。

Lock介面中的方法:

  • void lock() 獲取鎖。

  • void unlock() 釋放鎖。

public class RunnableImpl implements Runnable {
    private int ticket = 100;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            l.lock();
            if (ticket > 0) {
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName() + "--->正在賣第:" + ticket + "張票");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    l.unlock();
                }
            }
        }
    }
}

4.5、等待喚醒機制

等待喚醒案例:執行緒之間的通訊

建立一個顧客執行緒(消費者):告知老闆要的包子的種類和數量,呼叫wait方法,放棄cpu的執行,進入到waiting狀態(無限等待)

建立一個老闆執行緒(生產者):花了5秒做包子,做好包子之後,呼叫notify方法,喚醒顧客吃包子

注意:

  • 顧客和老闆執行緒必須使用同步程式碼塊包裹起來,保證等待和喚醒只能有一個在執行

  • 同步使用的鎖物件必須保證唯一

  • 只有鎖物件才能呼叫wait和notify方法

public class DemoWaitAndNotify {
    public static void main(String[] args) {
        Object o = new Object();
        new Thread() {
            @Override
            public void run() {
                synchronized (o){
                    System.out.println("告訴老闆要的包子的數量和種類");
                    try {
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("包子已經做好了 ,開吃");
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o){
                    System.out.println("老闆五秒後做好包子,告訴顧客可以吃了");
                    o.notify();
                }
            }
        }.start();

    }
}

進入到Timewaiting(計時等待)有兩種方式

  • 使用sleep(Long m)方法,在毫秒值結束之後,執行緒睡醒進入到Runnable/BLocked狀態

  • 使用wait(Long m)方法, wait方法如果在毫秒值結束之後,還沒有被notify響醒,就會自動醒來,執行緒睡醒進入到RunnabLe/BLoched狀態

喚醒的方法:

  • void notify()喚醒在此物件監視器上等待的單個執行緒。

  • void notifyAll()喚醒在此物件監視器上等待的所有執行緒。

吃包子案例

public class BaoZi {
    String pi;
    String xian;
    Boolean flat =false;
}
public class BaoZiPu extends Thread{
    private BaoZi bz;

    public BaoZiPu(BaoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (bz) {
                if (bz.flat == false) {
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("吃貨正在吃:" + bz.pi + "、" + bz.xian + "的包子");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                bz.flat = false;
                bz.notify();
                System.out.println("已經把:" + bz.pi + "、" + bz.xian + "的包子吃完了,包子鋪快繼續生產");
                System.out.println("----------------------------------");
            }
        }
    }
}
public class ChiHuo extends Thread{
    private BaoZi bz;

    public ChiHuo(BaoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        int count = 0;
        while (true) {
            synchronized (bz) {
                if (bz.flat == true) {
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (count % 2 == 0) {
                    bz.pi = "薄皮";
                    bz.xian = "豬肉";
                } else {
                    bz.pi = "冰皮";
                    bz.xian = "牛肉";
                }
                count++;
                System.out.println("包子鋪正在生產:" + bz.pi + "、" + bz.xian + "的包子");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                bz.flat = true;
                bz.notify();
                System.out.println("包子鋪已經生產好了:" + bz.pi + "、" + bz.xian + "的包子,可以開吃了!");
            }
        }
    }
}
public class Demo {
    public static void main(String[] args) {
        BaoZi bz = new BaoZi();
        new BaoZiPu(bz).start();
        new ChiHuo(bz).start();
    }
}