真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

java高并發(fā)系列-第1天:必須知道的幾個概念

同步(Synchronous)和異步(Asynchronous)

同步和異步通常來形容一次方法調(diào)用,同步方法調(diào)用一旦開始,調(diào)用者必須等到方法調(diào)用返回后,才能繼續(xù)后續(xù)的行為。異步方法調(diào)用更像一個消息傳遞,一旦開始,方法調(diào)用就會立即返回,調(diào)用者就可以繼續(xù)后續(xù)的操作。而異步方法通常會在另外一個線程中“真實”地執(zhí)行。整個過程,不會阻礙調(diào)用者的工作。

專注于為中小企業(yè)提供網(wǎng)站制作、成都網(wǎng)站制作服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)南雄免費做網(wǎng)站提供優(yōu)質(zhì)的服務。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了1000多家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。

如圖:

java高并發(fā)系列 - 第1天:必須知道的幾個概念

上圖中顯示了同步方法調(diào)用和異步方法調(diào)用的區(qū)別。對于調(diào)用者來說,異步調(diào)用似乎是一瞬間就完成的。如果異步調(diào)用需要返回結(jié)果,那么當這個異步調(diào)用真實完成時,則會通知調(diào)用者。

打個比方,比如購物,如果你去商場買空調(diào),當你到了商場看重了一款空調(diào),你就向售貨員下單。售貨員去倉庫幫你調(diào)配物品。這天你熱的是在不行了,就催著商家趕緊給你送貨,于是你就在商店里面候著他們,直到商家把你和空調(diào)一起送回家,一次愉快的購物就結(jié)束了。這就是同步調(diào)用。

不過,如果我們趕時髦,就坐在家里打開電腦,在電腦上訂購了一臺空調(diào)。當你完成網(wǎng)上支付的時候,對你來說購物過程已經(jīng)結(jié)束了。雖然空調(diào)還沒有送到家,但是你的任務已經(jīng)完成了。商家接到你的訂單后,就會加緊安平送貨,當然這一切已經(jīng)跟你無關了。你已經(jīng)支付完成,想干什么就能去干什么,出去溜幾圈都不成問題,等送貨上門的時候,接到商家的電話,回家一趟簽收就完事了。這就是異步調(diào)用。

并發(fā)(Concurrency)和并行(Parallelism)

并發(fā)和并行是兩個非常容易被混淆的概念。他們都可以表示兩個或者多個任務一起執(zhí)行,但是側(cè)重點有所不同。并發(fā)偏重于多個任務交替執(zhí)行,而多個任務之間有可能還是串行的,而并行是真正意義上的“同時執(zhí)行”,下圖很好地詮釋了這點。

java高并發(fā)系列 - 第1天:必須知道的幾個概念

大家排隊在一個咖啡機上接咖啡,交替執(zhí)行,是并發(fā);兩臺咖啡機上面接咖啡,是并行。

從嚴格意義上來說,并行的多任務是真的同時執(zhí)行,而對于并發(fā)來說,這個過程只是交替的,一會執(zhí)行任務A,一會執(zhí)行任務B,系統(tǒng)會不停地在兩者之間切換。但對于外部觀察者來說,即使多個任務之間是串行并發(fā)的,也會造成多任務間并行執(zhí)行的錯覺。

并發(fā)說的是在一個時間段內(nèi),多件事情在這個時間段內(nèi)交替執(zhí)行。

并行說的是多件事情在同一個時刻同事發(fā)生。

實際上,如果系統(tǒng)內(nèi)只有一個CPU,而使用多進程或者多線程任務,那么真實環(huán)境中這些任務不可能是真實并行的,畢竟一個CPU一次只能執(zhí)行一條指令,在這種情況下多進程或者多線程就是并發(fā)的,而不是并行的(操作系統(tǒng)會不停地切換多任務)。真實的并行也只可能出現(xiàn)在擁有多個CPU的系統(tǒng)中(比如多核CPU)。

臨界區(qū)

臨界區(qū)用來表示一種公共資源或者說共享數(shù)據(jù),可以被多個線程使用,但是每一次只能有一個線程使用它,一旦臨界區(qū)資源被占用,其他線程要想使用這個資源就必須等待。

比如,一個辦公室里有一臺打印機,打印機一次只能執(zhí)行一個任務。如果小王和×××同時需要打印文件,很明顯,如果小王先發(fā)了打印任務,打印機就開始打印小王的文件,×××的任務就只能等待小王打印結(jié)束后才能打印,這里的打印機就是一個臨界區(qū)的例子。

在并行程序中,臨界區(qū)資源是保護的對象,如果意外出現(xiàn)打印機同時執(zhí)行兩個任務的情況,那么最有可能的結(jié)果就是打印出來的文件是損壞的文件,它既不是小王想要的,也不是×××想要的。

阻塞(Blocking)和非阻塞(Non-Blocking)

阻塞和非阻塞通常用來形容很多線程間的相互影響。比如一個線程占用了臨界區(qū)資源,那么其他所有需要這個資源的線程就必須在這個臨界區(qū)中等待。等待會導致線程掛起,這種情況就是阻塞。此時,如果占用資源的線程一直不愿意釋放資源,那么其他線程阻塞在這個臨界區(qū)上的線程都不能工作。

非阻塞的意思與之相反,它強調(diào)沒有一個線程可以妨礙其他線程執(zhí)行,所有的線程都會嘗試不斷向前執(zhí)行。

死鎖(Deadlock)、饑餓(Starvation)和活鎖(Livelock)

死鎖、饑餓活鎖都屬于多線程的活躍性問題。如果發(fā)現(xiàn)上述幾種情況,那么相關線程就不再活躍,也就是說它可能很難再繼續(xù)往下執(zhí)行了。

死鎖應該是最糟糕的一種情況了(當然,其他幾種情況也好不到哪里去),如下圖顯示了一個死鎖的發(fā)生:

java高并發(fā)系列 - 第1天:必須知道的幾個概念

A、B、C、D四輛小車都在這種情況下都無法繼續(xù)行駛了。他們彼此之間相互占用了其他車輛的車道,如果大家都不愿意釋放自己的車道,那么這個狀況將永遠持續(xù)下去,誰都不可能通過,死鎖是一個很嚴重的并且應該避免和實時小心的問題,后面的文章中會做更詳細的討論。

饑餓是指某一個或者多個線程因為種種原因無法獲得所要的資源,導致一直無法執(zhí)行。比如它的優(yōu)先級可能太低,而高優(yōu)先級的線程不斷搶占它需要的資源,導致低優(yōu)先級線程無法工作。在自然界中,母雞給雛鳥喂食很容易出現(xiàn)這種情況:由于雛鳥很多,食物有限,雛鳥之間的事務競爭可能非常厲害,經(jīng)常搶不到事務的雛鳥有可能被餓死。線程的饑餓非常類似這種情況。此外,某一個線程一直占著關鍵資源不放,導致其他需要這個資源的線程無法正常執(zhí)行,這種情況也是饑餓的一種。于死鎖想必,饑餓還是有可能在未來一段時間內(nèi)解決的(比如,高優(yōu)先級的線程已經(jīng)完成任務,不再瘋狂執(zhí)行)。

活鎖是一種非常有趣的情況。不知道大家是否遇到過這么一種場景,當你要做電梯下樓時,電梯到了,門開了,這是你正準備出去。但很不巧的是,門外一個人當著你的去路,他想進來。于是,你很禮貌地靠左走,禮讓對方。同時,對方也非常禮貌的靠右走,希望禮讓你。結(jié)果,你們倆就又撞上了。于是乎,你們都意識到了問題,希望盡快避讓對方,你立即向右邊走,同時,他立即向左邊走。結(jié)果,又撞上了!不過介于人類的智慧,我相信這個動作重復兩三次后,你應該可以順利解決這個問題。因為這個時候,大家都會本能地對視,進行交流,保證這種情況不再發(fā)生。但如果這種情況發(fā)生在兩個線程之間可能就不那么幸運了。如果線程智力不夠。且都秉承著“謙讓”的原則,主動將資源釋放給他人使用,那么久會導致資源不斷地在兩個線程間跳動,而沒有一個線程可以同時拿到所有資源正常執(zhí)行。這種情況就是活鎖。

死鎖的例子

package com.jvm.visualvm;

/**
 * Java干貨鋪子,只生產(chǎn)干貨,公眾號:javacode2018
 */
public class Demo4 {

    public static void main(String[] args) {
        Obj1 obj1 = new Obj1();
        Obj2 obj2 = new Obj2();
        Thread thread1 = new Thread(new SynAddRunalbe(obj1, obj2, 1, 2, true));
        thread1.setName("thread1");
        thread1.start();
        Thread thread2 = new Thread(new SynAddRunalbe(obj1, obj2, 2, 1, false));
        thread2.setName("thread2");
        thread2.start();
    }

    /**
     * 線程死鎖等待演示
     */
    public static class SynAddRunalbe implements Runnable {
        Obj1 obj1;
        Obj2 obj2;
        int a, b;
        boolean flag;

        public SynAddRunalbe(Obj1 obj1, Obj2 obj2, int a, int b, boolean flag) {
            this.obj1 = obj1;
            this.obj2 = obj2;
            this.a = a;
            this.b = b;
            this.flag = flag;
        }

        @Override
        public void run() {
            try {
                if (flag) {
                    synchronized (obj1) {
                        Thread.sleep(100);
                        synchronized (obj2) {
                            System.out.println(a + b);
                        }
                    }
                } else {
                    synchronized (obj2) {
                        Thread.sleep(100);
                        synchronized (obj1) {
                            System.out.println(a + b);
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static class Obj1 {
    }

    public static class Obj2 {
    }
}

運行上面代碼,可以通過jstack查看到死鎖信息:

"thread2" #13 prio=5 os_prio=0 tid=0x0000000029225000 nid=0x3c94 waiting for monitor entry [0x0000000029c9f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.jvm.visualvm.Demo4$SynAddRunalbe.run(Demo4.java:50)
    - waiting to lock <0x00000007173d40f0> (a com.jvm.visualvm.Demo4$Obj1)
    - locked <0x00000007173d6310> (a com.jvm.visualvm.Demo4$Obj2)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - None

"thread1" #12 prio=5 os_prio=0 tid=0x0000000029224800 nid=0x6874 waiting for monitor entry [0x0000000029b9f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.jvm.visualvm.Demo4$SynAddRunalbe.run(Demo4.java:43)
    - waiting to lock <0x00000007173d6310> (a com.jvm.visualvm.Demo4$Obj2)
    - locked <0x00000007173d40f0> (a com.jvm.visualvm.Demo4$Obj1)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - None

thread1持有com.jvm.visualvm.Demo4$Obj1的鎖,等待獲取com.jvm.visualvm.Demo4$Obj2的鎖
thread2持有com.jvm.visualvm.Demo4$Obj2的鎖,等待獲取com.jvm.visualvm.Demo4$Obj1的鎖,兩個線程相互等待獲取對方持有的鎖,出現(xiàn)死鎖。

饑餓死鎖的例子

package com.jvm.jconsole;

import java.util.concurrent.*;

/**
 * Java干貨鋪子,只生產(chǎn)干貨,公眾號:javacode2018
 */
public class ExecutorLock {
    private static ExecutorService single = Executors.newSingleThreadExecutor();

    public static class AnotherCallable implements Callable {
        @Override
        public String call() throws Exception {
            System.out.println("in AnotherCallable");
            return "annother success";
        }
    }

    public static class MyCallable implements Callable {
        @Override
        public String call() throws Exception {
            System.out.println("in MyCallable");
            Future submit = single.submit(new AnotherCallable());
            return "success:" + submit.get();
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable task = new MyCallable();
        Future submit = single.submit(task);
        System.out.println(submit.get());
        System.out.println("over");
        single.shutdown();
    }
}

執(zhí)行代碼,輸出:

in MyCallable

使用jstack命令查看線程堆棧信息:

"pool-1-thread-1" #12 prio=5 os_prio=0 tid=0x0000000028e3d000 nid=0x58a4 waiting on condition [0x00000000297ff000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x0000000717921bf0> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
    at java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at com.jvm.jconsole.ExecutorLock$MyCallable.call(ExecutorLock.java:25)
    at com.jvm.jconsole.ExecutorLock$MyCallable.call(ExecutorLock.java:20)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - <0x00000007173f2690> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"main" #1 prio=5 os_prio=0 tid=0x00000000033e4000 nid=0x5f94 waiting on condition [0x00000000031fe000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007173f1d48> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
    at java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at com.jvm.jconsole.ExecutorLock.main(ExecutorLock.java:32)

   Locked ownable synchronizers:
    - None

java高并發(fā)系列 - 第1天:必須知道的幾個概念

堆棧信息結(jié)合圖中的代碼,可以看出主線程在32行處于等待中,線程池中的工作線程在25行處于等待中,等待獲取結(jié)果。由于線程池是一個線程,AnotherCallable得不到執(zhí)行,而被餓死,最終導致了程序死鎖的現(xiàn)象。

java高并發(fā)系列連載中,總計估計會有四五十篇文章,可以關注公眾號:javacode2018,獲取最新文章。

java高并發(fā)系列 - 第1天:必須知道的幾個概念


網(wǎng)站名稱:java高并發(fā)系列-第1天:必須知道的幾個概念
本文來源:http://weahome.cn/article/jsgids.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部