Java多線程編程(1)

1、進程和線程

串行和並行

串行是指多個任務時,各個任務按順序執行,完成一個之後才能進行下一個。

並行指的是多個任務可以同時執行。異步是多個任務並行的前提條件。

並行和併發

多個cpu實例或者多臺機器同時執行一段處理邏輯,是真正的同時。

通過cpu調度算法,讓用戶看上去同時執行,實際上從cpu操作層面不是真正的同時。

進程和線程

進程具有獨立的執行環境。 進程具有一套完整的私有基本運行時資源。 每個進程都有自己的存儲空間。

線程有時稱爲輕量級進程。 創建新線程所需的資源少於創建新進程的資源。

線程狀態

初始(NEW):新創建了一個線程對象,但還沒有調用start()方法。

運行(RUNNABLE):Java線程中將就緒(ready)和運行中(running)兩種狀態籠統的稱爲“運行”。

阻塞(BLOCKED):表示線程阻塞於鎖。

等待(WAITING):進入該狀態的線程需要等待其他線程做出一些特定動作(通知或中斷)。

超時等待(TIMED_WAITING):該狀態不同於WAITING,它可以在指定的時間後自行返回。

終止(TERMINATED):表示該線程已經執行完畢。

2、線程對象

線程定義:實現Runnable接口

提供一個Runnable對象。該 Runnable接口定義了一個方法,run用於包含在線程中執行的代碼。該Runnable對象將傳遞給Thread構造函數。

public class HelloRunnable implements Runnable {

    public void run() {
        System.out.println("HelloRunnable");
    }

    public static void main(String args[]) {
        Runnable runnable = new HelloRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }

}

線程定義:繼承Thread類

子類Thread。在Thread類自身實現Runnable,但其run方法不起作用。應用程序可以子類Thread提供自己的實現run。

public class HelloThread extends Thread {

    public void run() {
        System.out.println("HelloThread");
    }

    public static void main(String args[]) {
        HelloThread helloThread = new HelloThread();
        helloThread.start();
    }

}

線程命名

所有的線程程序的執行,每一次都是不同的運行結果,如果要想區分每一個線程,那麼久必須依靠線程的名字。對於線程的名字一般而言會在啓動之前進程定義,不建議對已經啓動的線程,進行更改名稱,或者爲不同線程設置重名的情況。

public class HelloRunnableName implements Runnable {
    @Override
    public void run() {
        System.out.println("你好:" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        HelloRunnableName helloRunnable = new HelloRunnableName();
        Thread thread = new Thread(helloRunnable, "線程1");
        System.out.println("線程名稱:" + thread.getName());
        thread.start();
    }
}
public class HelloThreadName extends Thread {
    public HelloThreadName(String name) {
        // super(name);
        this.setName(name);
    }
    @Override
    public void run() {
        super.run();
        System.out.println("你好:" + Thread.currentThread().getName());
    }
    public static void main(String[] args) {
        HelloThreadName helloThreadName = new HelloThreadName("線程1");
        System.out.println("線程名稱:" + helloThreadName.getName());
        helloThreadName.start();
    }
}

線程優先級

線程優先級的範圍是1~10,默認的優先級是5。10極最高。 “高優先級線程”被分配CPU的概率高於“低優先級線程”。

public class ThreadPriority implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("線程名稱:"
                    + Thread.currentThread().getName()
                    + ",線程優先級:"
                    + Thread.currentThread().getPriority()
                    + ",循環:" + i);
        }
    }
    public static void main(String[] args) {
        ThreadPriority threadPriority = new ThreadPriority();
        Thread thread1 = new Thread(threadPriority);
        thread1.setName("線程1");
        thread1.setPriority(Thread.MIN_PRIORITY);
        Thread thread2 = new Thread(threadPriority);
        thread2.setName("線程2");
        thread2.setPriority(Thread.MAX_PRIORITY);
        thread1.start();
        thread2.start();
    }
}

線程休眠:sleep方法

Thread.sleep使當前線程在指定時間段內暫停執行。這是使處理器時間可用於應用程序的其他線程或計算機系統上可能正在運行的其他應用程序的有效方法。

public class ThreadSleep implements Runnable {
    @Override
    public void run() {
        String info[] = {
                "春眠不覺曉",
                "處處聞啼鳥",
                "夜來風雨聲",
                "花落知多少"
        };
        for (int i = 0; i < info.length; i++) {
            System.out.println(info[i]);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        ThreadSleep threadSleep = new ThreadSleep();
        Thread thread = new Thread(threadSleep);
        thread.start();
    }
}

線程禮讓:yield方法

Thread類中提供了一種禮讓方法,使用yield()方法表示,它只是給當前正處於運行狀態下的線程一個提醒,告知它可以將資源禮讓給其他線程,但這僅僅是一種暗示,沒有任何一種機制保證當前線程會將資源禮讓。 yield()方法使具有同樣優先級的線程有進入可執行狀態的機會,噹噹前線程放棄執行權時會再度回到就緒狀態。

public class ThreadYield implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "開始了");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + "結束了");
    }

    public static void main(String[] args) {
        ThreadYield threadYield = new ThreadYield();
        Thread thread1 = new Thread(threadYield, "線程1");
        Thread thread2 = new Thread(threadYield, "線程2");
        thread1.start();
        thread2.start();
    }
}

線程聯合:join方法

join方法允許一個線程等待另一線程的完成。如果t是Thread正在執行其線程的對象, t.join(); 導致當前線程暫停執行,直到t的線程終止。重載join允許程序員指定等待時間。但是,與一樣sleep,join依賴於OS進行計時,因此不應該假定join它將完全按照您指定的時間等待。

public class ThreadJoin implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("子線程" + i);
        }
    }
    public static void main(String[] args) {
        ThreadJoin threadJoin = new ThreadJoin();
        Thread thread = new Thread(threadJoin);
        thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主線程main" + i);
            if(i == 90) {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

線程停止

停止一個線程通常意味着在線程處理任務完成之前停掉正在做的操作,也就是放棄當前的操作。 在 Java 中有以下 3 種方法可以終止正在運行的線程: 使用退出標識,使得線程正常退出,即當run方法完成後進程終止。 使用stop強行中斷線程(此方法爲作廢過期方法),不推薦使用。 使用interrupt方法中斷線程,不推薦使用。

public class ThreadStop implements Runnable {

    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("子線程" + i++);
        }

    }

    public void stop() {
        this.flag = false;
    }
    public static void main(String[] args) {
        ThreadStop threadStop = new ThreadStop();
        Thread thread = new Thread(threadStop);
        thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主線程main" + i);
            if (i == 90) {
                threadStop.stop();
                System.out.println("子線程停止了");
            }
        }
    }
}

守護線程

Java線程分爲兩種:用戶線程和守護線程。 用戶線程可以認爲是系統的工作線程,它會完成這個程序要完成的業務員操作。 守護線程是一種特殊的線程,就和它的名字一樣,它是系統的守護者,在後臺默默完成一些系統性的服務,比如垃圾回收線程。 如果用戶線程全部結束,則意味着這個程序無事可做。守護線程要守護的對象已經不存在了,那麼整個應用程序就結束了。

public class ThreadDaemon {
    public static void main(String[] args) {
        Daemon daemon = new Daemon();
        Thread thread1 = new Thread(daemon);
        thread1.setDaemon(true);
        thread1.start();
        Me me = new Me();
        Thread thread2 = new Thread(me);
        thread2.start();
    }
}
class Me implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我的努力奔跑" + i);
        }
    }
}
class Daemon implements Runnable {
    @Override
    public void run() {
        int i = 0;
        while (true) {
            System.out.println("我的守護你" + i++);
        }
    }
}

龜兔賽跑

public class Race implements Runnable {
    private static String winner;
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if ("兔子".equals(Thread.currentThread().getName()) && i % 10 == 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            boolean flag = gameOver(i);
            if (flag) { break; }
            System.out.println(Thread.currentThread().getName() + "跑了" + i + "米");
        }
    }
public boolean gameOver(int meters) {
        if (winner != null) {
            return true;
        }
        if (meters >= 100) {
            winner = Thread.currentThread().getName();
            System.out.println("勝利者是" + winner);
            return true;
        }
        return false;
    }
    public static void main(String[] args) {
        Race race = new Race();
        Thread thread1 = new Thread(race, "烏龜");
        thread1.start();
        Thread thread2 = new Thread(race, "兔子");
        thread2.start();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章