java進(jìn)階(二):多線程

1、多線程的目的

即“最大限度的利用CPU資源”,當(dāng)某一線程的處理不需要占用CPU而只和I/O等資源打交道時,讓需要占用CPU資源的其他線程有機(jī)會獲得CPU資源。

2、創(chuàng)建線程

方法一:
通過繼承Thread類創(chuàng)建線程

  • 普通線程如果繼承自Thread類,就成為了一個線程類,并可以通過該類的start方法來啟動線程,執(zhí)行線程代碼。
    *Thread類的子類可以直接實例化,但在子類中必須覆蓋run方法才能真正運(yùn)行線程代碼。
class MyThread extends Thread {
    private int i = 0;
    @Override
    public void run() {
        for (i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Thread myThread1 = new MyThread();     // 創(chuàng)建一個新的線程  myThread1  此線程進(jìn)入新建狀態(tài)
                Thread myThread2 = new MyThread();     // 創(chuàng)建一個新的線程 myThread2 此線程進(jìn)入新建狀態(tài)
                myThread1.start();                     // 調(diào)用start()方法使得線程進(jìn)入就緒狀態(tài)
                myThread2.start();                     // 調(diào)用start()方法使得線程進(jìn)入就緒狀態(tài)
            }
        }
    }
}

方法二:
通過實現(xiàn)Runnable接口創(chuàng)建線程

  • 實現(xiàn)Runnable接口的類必須借助Thread類才能創(chuàng)建線程。通過Runnable接口創(chuàng)建線程分為兩步:
    1、創(chuàng)建實現(xiàn)Runnable接口的類的實例。
    2、創(chuàng)建一個Thread類對象,將第一步得到的實例作為參數(shù)傳入Thread類的構(gòu)造方法。
  • 通過Tread類的start方法啟動線程。
class MyRunnable implements Runnable {
    private int i = 0;
    @Override
    public void run() {
        for (i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

public class ThreadTest {

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Runnable myRunnable = new MyRunnable(); // 創(chuàng)建一個Runnable實現(xiàn)類的對象
                Thread thread1 = new Thread(myRunnable); // 將myRunnable作為Thread target創(chuàng)建新的線程
                Thread thread2 = new Thread(myRunnable);
                thread1.start(); // 調(diào)用start()方法使得線程進(jìn)入就緒狀態(tài)
                thread2.start();
            }
        }
    }
}

當(dāng)然,還可以直接使用匿名內(nèi)部類,方法十分簡便,僅需重寫run方法,例如:

/*
 * 匿名內(nèi)部類的格式:
 */
public class ThreadDemo {
    public static void main(String[] args) {
        // 繼承thread類實現(xiàn)多線程
        new Thread() {
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println(Thread.currentThread().getName() + "--"
                            + x);
                }
            }
        }.start();
        ;

        // 實現(xiàn)runnable借口,創(chuàng)建多線程并啟動
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println(Thread.currentThread().getName() + "--"
                            + x);
                }
            }
        }) {
        }.start();

        // 更有難度的,在Thread匿名內(nèi)部類的里面再一次重寫run方法
        //在實際運(yùn)行時的結(jié)果是 hello+x。以thread的run方法為準(zhǔn)。但是此處無意義
        new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                for (int x = 0; x < 100; x++) {
                    System.out.println("java" + "--" + x);
                }

            }
        }) {
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println("hello" + "--" + x);
                }
            }
        }.start();
    }
}

3、線程完整生命周期

生命周期



4、線程同步

線程同步是為了防止多個線程訪問一個數(shù)據(jù)對象時,對數(shù)據(jù)造成破壞。

注意:用synchronized關(guān)鍵字聲明的靜態(tài)方法,同時只能被一個執(zhí)行線程訪問,但是其他線程可以訪問這個對象的非靜態(tài)方法。即:兩個線程可以同時訪問一個對象的兩個不同的synchronized方法,其中一個是靜態(tài)方法,一個是非靜態(tài)方法。


//示例
public synchronized void addAmount(double amount) {
}

synchronized(this){
}

5、線程通信

假設(shè)有這么一個問題,要求編寫兩個線程,一個線程打印125,另一個線程打印字母AZ,打印順序為12A34B56C……5152Z,這就要求使用線程間的通信,解決的方法有以下幾種:

  • 使用一個共享變量控制,利用最基本的synchronized、notify、wait
public class MethodOne {
    private final ThreadToGo threadToGo = new ThreadToGo();
    public Runnable newThreadOne() {
        final String[] inputArr = Helper.buildNoArr(52);
        return new Runnable() {
            private String[] arr = inputArr;
            public void run() {
                try {
                    for (int i = 0; i < arr.length; i=i+2) {
                        synchronized (threadToGo) {
                            while (threadToGo.value == 2)
                                threadToGo.wait();
                            Helper.print(arr[i], arr[i + 1]);
                            threadToGo.value = 2;
                            threadToGo.notify();
                        }
                    }
                } catch (InterruptedException e) {
                    System.out.println("Oops...");
                }
            }
        };
    }
    public Runnable newThreadTwo() {
        final String[] inputArr = Helper.buildCharArr(26);
        return new Runnable() {
            private String[] arr = inputArr;
            public void run() {
                try {
                    for (int i = 0; i < arr.length; i++) {
                        synchronized (threadToGo) {
                            while (threadToGo.value == 1)
                                threadToGo.wait();
                            Helper.print(arr[i]);
                            threadToGo.value = 1;
                            threadToGo.notify();
                        }
                    }
                } catch (InterruptedException e) {
                    System.out.println("Oops...");
                }
            }
        };
    }
    class ThreadToGo {
        int value = 1;
    }
    public static void main(String args[]) throws InterruptedException {
        MethodOne one = new MethodOne();
        Helper.instance.run(one.newThreadOne());
        Helper.instance.run(one.newThreadTwo());
        Helper.instance.shutdown();
    }
}
  • 利用volatile關(guān)鍵字
    volatile修飾的變量值直接存在main memory里面,子線程對該變量的讀寫直接寫入main memory,而不是像其它變量一樣在local thread里面產(chǎn)生一份copy。volatile能保證所修飾的變量對于多個線程可見性,即只要被修改,其它線程讀到的一定是最新的值。
public class MethodThree {
    private volatile ThreadToGo threadToGo = new ThreadToGo();
    class ThreadToGo {
        int value = 1;
    }
    public Runnable newThreadOne() {
        final String[] inputArr = Helper.buildNoArr(52);
        return new Runnable() {
            private String[] arr = inputArr;
            public void run() {
                for (int i = 0; i < arr.length; i=i+2) {
                    while(threadToGo.value==2){}
                    Helper.print(arr[i], arr[i + 1]);
                    threadToGo.value=2;
                }
            }
        };
    }
    public Runnable newThreadTwo() {
        final String[] inputArr = Helper.buildCharArr(26);
        return new Runnable() {
            private String[] arr = inputArr;
            public void run() {
                for (int i = 0; i < arr.length; i++) {
                    while(threadToGo.value==1){}
                    Helper.print(arr[i]);
                    threadToGo.value=1;
                }
            }
        };
    }
    public static void main(String args[]) throws InterruptedException {
        MethodThree three = new MethodThree();
        Helper.instance.run(three.newThreadOne());
        Helper.instance.run(three.newThreadTwo());
        Helper.instance.shutdown();
    }
}

6、線程死鎖

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

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

  • 進(jìn)程和線程 進(jìn)程 所有運(yùn)行中的任務(wù)通常對應(yīng)一個進(jìn)程,當(dāng)一個程序進(jìn)入內(nèi)存運(yùn)行時,即變成一個進(jìn)程.進(jìn)程是處于運(yùn)行過程中...
    勝浩_ae28閱讀 5,258評論 0 23
  • 進(jìn)程和線程 進(jìn)程 所有運(yùn)行中的任務(wù)通常對應(yīng)一個進(jìn)程,當(dāng)一個程序進(jìn)入內(nèi)存運(yùn)行時,即變成一個進(jìn)程.進(jìn)程是處于運(yùn)行過程中...
    小徐andorid閱讀 2,994評論 3 53
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,112評論 1 18
  • 單任務(wù) 單任務(wù)的特點(diǎn)是排隊執(zhí)行,也就是同步,就像再cmd輸入一條命令后,必須等待這條命令執(zhí)行完才可以執(zhí)行下一條命令...
    Steven1997閱讀 1,357評論 0 6
  • 穩(wěn)步發(fā)展 連鎖經(jīng)營發(fā)展超過預(yù)期,全榮城布點(diǎn)的工作,提上議程,布點(diǎn)嗎?當(dāng)然先要在好的點(diǎn)布。向天連...
    沙漠里的趵突泉閱讀 335評論 0 0

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