初識多線程

多線程學習

  • 什麼是線程
  • Java多線程的使用java

    什麼是線程

    這裏先引用一下百度給出的概念算法

    線程是系統可以進行運算調度的最小單位。他被包含在進程只中,是進程中的實際運做單位。shell

這裏只摘取簡單的引用,便於通俗的理解,畢竟百度百科上面的東西太過於專業化,專業名詞太多。微信

上面有一個名詞進程,這裏解釋一下進程多線程

通常咱們打開一個軟件,好比qq,微信,這個時候就啓動了一個進程,在Windows任務管理器中咱們能夠看到它們
進程
紅框部分就是一個進程jvm

好了咱們大概算是通俗的理解了什麼是進程
在當代面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。ide

這裏用一個簡單的例子演示一下函數

public class test1 {

    private static class ther extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    TimeUnit.MICROSECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("啓動了一個線程");
            }
        }
    }

    public static void main(String[] args)  {
        ther ther = new ther();
        ther.start();
        for (int i = 0; i < 10; i++) {
            try {
                TimeUnit.MICROSECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("主函數執行了");
        }
    }
}

咱們看一下執行結果,暫時不要理會如今的寫法學習

主函數執行了
啓動了一個線程
主函數執行了
啓動了一個線程
主函數執行了
啓動了一個線程
啓動了一個線程
主函數執行了
主函數執行了
啓動了一個線程
主函數執行了
啓動了一個線程
主函數執行了
啓動了一個線程
主函數執行了
啓動了一個線程
啓動了一個線程
主函數執行了
主函數執行了
啓動了一個線程

咱們能夠看見它是交替運行的
平時咱們的代碼都是串行的,也就是順序執行,而如今這鐘狀況就是並行的狀態,這就是線程一個比較直觀的概念操作系統

Java多線程的使用

線程的建立

這裏列舉幾種線程經常使用的幾種方式

經過繼承Thread而後實現它的run()方法來進行建立線程

private static class exThread extends Thread{
        @Override
        public void run() {
            System.out.println("繼承thread實現run方法建立線程");
        }
    }

經過實現Runnable建立一個線程

private static class impRunnable implements Runnable{
        @Override
        public void run() {
            System.out.println("經過實現Runnable建立一個線程");
        }
    }

經過實現Callable建立一個線程,這種建立方式是有返回池的

private static class impCallable implements Callable{
        @Override
        public Object call() throws Exception {
            System.out.println("經過實現Callable建立一個線程,它是有放回值的");
            return "ssuccess";
        }
    }

線程的啓動

這裏列舉5鍾啓動線程的方式

public static void main(String[] args) {
        new exThread().start();//經過直接建立對象而後調用start();方法啓動一個線程
        new Thread(new exThread()).start();//經過new一個線程類而後傳入須要啓動的線程,而後調用線程類的start方法啓動
        new Thread(()->{
            System.out.println("lambda表達式建立並啓動一個線程");
        }).start();
        Thread thread = new Thread(new FutureTask<String>(new impCallable()));
        thread.start();//經過newThread傳入FutureTask啓動
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(()->{
            System.out.println("線程池啓動並建立");
        });
        executorService.shutdown();//中止
    }

執行結果以下

繼承thread實現run方法建立線程
繼承thread實現run方法建立線程
lambda表達式建立並啓動一個線程
經過實現Callable建立一個線程,它是有放回值的
線程池啓動並建立

稍微總結一下:
線程經常使用的建立並啓動的方式有兩種
1.經過new Thread().start();
2.經過new Thread(Runnable).start();
還有一種是使用線程池,不過本質上仍是使用上面的兩種方式
固然你也可使用lambda表達式,本質上沒什麼區別寫法不一樣而已

線程的方法

sleep線程休眠

這個方法頗有意思,好比說,你可在你的代碼某些業務中加個線程休眠5分鐘,而後老闆說你這個程序太慢了,你就能夠說加錢調優,還能按照百分比調整程序的運行速度。是否是很實用?
開個玩笑,開個玩笑
咱們來看下使用方式

public static void main(String[] args) {
        testSleep();
    }
    static void  testSleep(){
        new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我先睡一會");
        }).start();
    }

執行結果咱們能夠看出它過了一會才執行
線程休眠之後何時醒過來,根據sleep裏的參數決定,時間到了就醒了
線程休眠通俗理解:就是當前我不運行了,別的線程照樣能夠運行

Yield方法,翻譯過來是讓步的意思

咱們先來看一下用法而後在來解釋一下含義

static void testYield(){
        new Thread(()->{
            for (int i=0;i<100;i++){
                System.out.println("A----"+i);
                if (i%10==0){
                    Thread.yield();
                }
            }
        }).start();;

        new Thread(()->{
            for (int i=0;i<100;i++){
                System.out.println("B----"+i);
                if (i%10==0){
                    Thread.yield();
                }
            }
        }).start();;
    }

這裏就不演示打印結果了,不是頗有表明性
講一下這個方法的做用

一個線程在執行過程當中假如調用yieid這個方法,當前線程會先中止下來進入等待隊列,這也就是讓步的意思,可是當回到等待隊列之後,在系統的調度算法裏,它依然有可能把剛回到等待隊列的線程繼續執行,固然更大的可能性仍是先執行以前等待隊列的線程,因此yieid的意思是,我雖然讓出了,可是能不能搶到執行機會我無論。

join方法,也就是加入的意思

先看寫法

Thread thread2 = new Thread(() -> {
            System.out.println("thread1執行了一下,如今到我執行了");
        });

        Thread thread1 = new Thread(() -> {
            System.out.println("我先執行一次,而後等下一個線程執行完在執行");
            try {
                thread2.join();
                System.out.println("thread2------執行完了,到我執行了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();

在當前線程1中加入你要執行的線程2,等線程2執行完了在繼續執行線程1,這樣達到了按照順序執行線程的目的,固然,你還能夠在線程2中去join線程3,以此類推,其實就是將並行的線程串聯起來了。

線程狀態

常見的6種線程狀態

當咱們在new一個線程的時候,可是尚未調用start()方法的時候,該線程處於新建狀態

線程對象調用start方法的時候,它會被線程調度器進行執行,這個時候線程就已經交給操做系統來執行了,在操做系統執行的過程當中,這整個狀態叫作Runnable,Runnable內部又有兩個狀態,一個是Ready就緒狀態,一個是Running運行狀態,就緒狀態故名思意,我已經準備好了,可是還沒運行,這個時候是cpu去處理何時去運行的。當真正交給cpu去運行的時候,當前線程就處理Running狀態了。(當調用yield方法時,當前線程就會由Running狀態,變爲Ready狀態,當被cpu再次執行的時候又會進入Running狀態)

若是線程順利執行完了就會進入Teminated結束狀態,結束之後當前線程的使命就結束了,狀態沒法回退。

在Runnable狀態還存在其餘幾種狀態,TimeWaiting等待,Waiting等待Blocked阻塞
在同步代碼塊中,沒有獲得鎖就會進入Blocke阻塞狀態,當得到鎖之後就進入Ready就緒狀態。
在線程運行過程當中若是調用了wait(),join(),LockSupport.park()就會進入到Waiting狀態,調用notifiall(),LockSupport.unpark()就會回到Running狀態。
TimeWaiting,看名字就知道是按照時間等待,等時間到了本身會回去,Thread.sleep(time),wait(time),jion(time),LockSupport.parkNanos(),LockSupport.parkUntil()這些都是關於時間等待的方法。

上面的全部狀態均是由jvm進行管理的,jvm在使用線程的時候也要通過操做系統,jvm就是一個在操做系統上運行的程序。
線程掛起就是在當前線程執行過程當中cpu去執行另一個線程了,這屬於cpu的調度,當在執行另一個線程的時候,當前線程就是被掛起了。

這裏是我畫的一個簡陋的流程圖

線程狀態

相關文章
相關標籤/搜索