還不懂Java高併發的,建議看看這篇阿里大佬的總結,非常詳細

前言

進程是計算機中程序關於某幾何數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位。是操作系統結構的基礎

線程可以說是輕量級的進程,是程序執行的最小單位,使用多線程而不用多進程去進行併發程序的設計,是因為線程之間的切換與調度的成本遠小於進程。

線程的幾種狀態

<code>New狀態表示剛剛創建的線程,這種線程還沒有開始執行
RUNNABLE:當線程創建好之後,調用線程的start方法就會進入就緒狀態。
BLOCKED:當線程運行過程如果遇到了Syschronized就會進入阻塞狀態。
TIMED_WATING:表示等待狀態,有時間限制的(sleep)
WAITING:表示進入一個無時間顯示的等待狀態(wait)
TERMINATED:表示結束狀態。

/<code>

線程的基本操作

新建線程

實現Runable接口或者new Thread

終止線程

為什麼不建議使用stop?

因為stop方法比較暴力,強行把執行的程序終止,可能會引發數據不一致的問題,Thread.stop()方法在結束線程時,會直接終止線程,並立即釋放這個線程的所持有的鎖。比如數據寫到一半,強行終止掉了,數據就會被破壞。

線程中斷

<code>interrupt() //中斷線程。相當於設置中斷標誌位
isInterrypted() //判斷是否被中斷
interrupted() //判斷是都被中斷,並清除當前的中斷狀態

/<code>
<code>
/<code>

Thread.sleep()方法由於中斷而拋出異常,此時它會清除中斷標記,如果不加處理,那麼下一次循環開始時,就無法捕獲這個異常,可以再次設置中斷標記來方便循環判斷。

等待和通知

當在一個對象實力上條用wait()方法之後。當前線程就會在這個對象上等待。在線程A中調用了obj.wait()方法,那麼變成A就會停止繼續執行,轉為等待狀態,直到其他線程調用了obj.notify()方法才有機會繼續執行(並不是一定)

如果一個線程調用了obj.wait()那麼它就會進入這個object的等待隊列,這個等待隊列可能會有多個線程,因為系統運行多個線程同時等待某一個對象,當obj.notify()方法被調用時,就會隨機選擇一個線程,將其喚醒,這個喚醒是完全隨機的。

notifyAll()方法的功能是喚醒所有在該對象等待隊列中等待的線程。

守護線程的finally不一定會執行。如果除守護線程外的所有線程都結束了,那麼守護線程就立即退出沒有執行finally代碼塊的機會。

掛起(suspend)和繼續(resume)執行

不推薦執行suspend(),因為該方法在導致線程暫停的同時,並不會釋放任何資源。影響其他想要訪問該資源的線程,直到當前線程使用resume操作,是當前線程繼續執行,但是此處有一個隱患。如果resume在suspend之前運行了,那麼被掛起的線程將不能繼續執行下去。

<code>public class BadSuspend {
    public static Object u = new Object();
    static ChangeObjectThread t1 = new ChangeObjectThread("t1");
    static ChangeObjectThread t2 = new ChangeObjectThread("t2");

    public static class ChangeObjectThread extends Thread {
        public ChangeObjectThread(String name){
            super.setName(name);
        }
        @Override
        public void run() {
            synchronized (u) {
                System.out.println("in "+getName());
                Thread.currentThread().suspend();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        t1.start();
        Thread.sleep(100);
        t2.start();
        t1.resume();
        t2.resume();//無法直到這一行先執行,還是Thread.currentThread().suspend();先執行
        t1.join();
        t2.join();
    }
}

/<code>

等待線程結束(join)和謙讓(yeild)

<code>public final synchronized void join(long millis) throws InterruptedException//有最大等待時長的等待

public final synchronized void join(long millis, int nanos)
throws InterruptedException//毫秒,加納秒級別的等待

public final void join() throws InterruptedException//表示無限期的等待

/<code>
<code>package com.atmb.me;

public class joinAndYeild {
    public volatile  static  int i =0;

    public static class myThread implements Runnable{
        @Override
        public void run() {
            for (int j = 0; j < 1000000; j++) {
                i+=1;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new myThread());
        thread.start();
        thread.join();//等待thread線程執行結束
        System.out.println(i);//結果為1000000
    }
}

/<code>
<code>    public static native void yield();

/<code>

這個方法一旦執行,就會使當前線程讓出cpu,讓出cpu之後,該線程會繼續進行cpu資源的爭奪,之後繼續正常運行。

線程組

<code>package com.atmb.me;

public class ThreadGroupTest implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getThreadGroup().getName()+"==="+Thread.currentThread().getName());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ThreadGroup group1 = new ThreadGroup("group1");
        Thread thread1 = new Thread(group1, new ThreadGroupTest());
        Thread thread2 = new Thread(group1, new ThreadGroupTest());
        thread1.start();
        thread2.start();
        System.out.println(group1.activeCount());//活躍線程數
        group1.list();
    }
}
<
2
group1===Thread-0
java.lang.ThreadGroup[name=group1,maxpri=10]
group1===Thread-1
    Thread[Thread-0,5,group1]
    Thread[Thread-1,5,group1]

/<code>

守護線程(Daemon)

守護線程要守護的對象已經不存在了,那麼整個應用程序就應該技術,因此當java應用內只有守護線程時,java虛擬機就會自然退出。

<code>package geym.ch2;

public class DaemonDemo {
    public static class DaemonT extends Thread{
        public void run(){
            while(true){
                System.out.println("I am alive");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t=new DaemonT();
        t.setDaemon(true);
        t.start();

//        Thread.sleep(2000);
    }
}

/<code>

設置守護線程,必須要在start之前設置,否則會得到異常信息。

線程優先級

Java中的線程可以有自己的優先級。優先級高的線程在競爭資源時,會更有優勢,更大概率搶佔到資源,java中線程優先級可以設置為1-10.
其中有三個靜態標量標識三個對應的優先級。

<code>    /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

/<code>
<code>public class PriorityDemo {
    public static class HightPriority extends Thread{
        static int count=0;
        public void run(){
            while(true){
                synchronized(PriorityDemo.class){
                    count++;
                    if(count>10000000){
                        System.out.println("HightPriority is complete");
                        break;
                    }
                }
            }
        }
    }
    public static class LowPriority extends Thread{
        static int count=0;
        public void run(){
            while(true){
                synchronized(PriorityDemo.class){
                    count++;
                    if(count>10000000){
                        System.out.println("LowPriority is complete");
                        break;
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread high=new HightPriority();
        LowPriority low=new LowPriority();
        high.setPriority(Thread.MIN_PRIORITY);
        low.setPriority(Thread.MAX_PRIORITY);
        low.start();
        high.start();
    }
}

/<code>

線程安全與關鍵字synchronized

synchronized

  • 指定加鎖對象,對給定的對象進行加鎖,
  • 用於實例方法,對當前的實例進行加鎖
  • 用於靜態方法,對當前類進行加鎖

錯誤的加鎖

<code>package com.atmb.me;

public class lockError implements Runnable {
    public static Integer i =0;
    public static lockError instance =  new lockError();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(instance);
        Thread thread2 = new Thread(instance);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(i);
    }

    @Override
    public void run() {
        for (int j = 0; j < 100000; j++) {
            synchronized (i){
                i+=1;
            }
        }
    }
}
<
142957

/<code>

原因在於Integer類型屬於不可變對象,一旦創建就不可能被改變,當integer對象賦值為新值時,當前引用指向的對象就改變了。

指令重排的前提

指令重排需要保證串行語義的一致性,指令重排不會使串行的語義邏輯發生問題。

指令重排的目的?

<code>為了減少中斷流水線

/<code>

那些指令不能重排

  • 程序順序原則,一個線程內保證語義的串行性
  • volatile規則:volatile變量的寫先與讀發生,寶整理volatile變量的可見性
  • 傳遞性:解鎖必然發生在隨後的加鎖前
  • 線程的start()方法先於它的動作
  • 線程的所有操作先於線程的終結(interrupt)
  • 線程的中斷(interrupt())先於被中斷線程的代碼
  • 對象的構造函數的執行,結束先於finalize()的方法

是否會釋放鎖

  • yield讓出cpu執行權,不會釋放鎖
  • sleep休眠時,不會釋放鎖
  • 調用wait方法之後,會釋放鎖,喚醒之後,會再次競爭鎖,然後執行wait()方法後的代碼
  • nofify nodifyall 對鎖沒有影響,一般放同步代碼塊的最後一行

最後

感謝你看到這裡,看完有什麼的不懂的可以在評論區問我,覺得文章對你有幫助的話記得給我點個贊,每天都會分享java相關技術文章或行業資訊,歡迎大家關注和轉發文章!


還不懂Java高併發的,建議看看這篇阿里大佬的總結,非常詳細


分享到:


相關文章: