最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java并發(fā)包JUC誕生及詳細(xì)內(nèi)容

 更新時間:2022年02月28日 10:40:37   作者:kl  
這篇文章主要為大家介紹了java并發(fā)包JUC的誕生及JUC增加的內(nèi)容詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步

前言

J.U.C是java包java.util.concurrent的簡寫,中文簡稱并發(fā)包,是jdk1.5新增用來編寫并發(fā)相關(guān)的基礎(chǔ)api。java從事者一定不陌生,同時,流量時代的今天,并發(fā)包也成為了高級開發(fā)面試時必問的一塊內(nèi)容,本篇內(nèi)容主要聊聊J.U.C背后的哪些事兒,然后結(jié)合LockSupport和Unsafe探秘下并發(fā)包更底層的哪些代碼,有可能是系列博文的一個開篇

關(guān)于JCP和JSR

JCP是Java Community Process的簡寫,是一種開發(fā)和修訂Java技術(shù)規(guī)范的流程,同時,我們提到JCP一般是指維護管理這套流程的組織,這個組織主要由Java開發(fā)者以及被授權(quán)的非盈利組織組成,他們掌管著Java的發(fā)展方向。JCP是Sun公司1998年12月8日提出的,旨在通過java社區(qū)的力量推進Java的發(fā)展。截止目前,已經(jīng)從1.0版本發(fā)展到了最新的2019年7月21日頒布的2.11版本。JCP流程中有四個主要階段,分別是啟動、發(fā)布草案、最終版本、維護,一個Java的新功能從啟動階段提出,到順利走完整套流程后,就會出現(xiàn)在下個版本的JDK中了。

JSR是Java Specification Requests的簡寫,是服務(wù)JCP啟動階段提出草案的規(guī)范,任何人注冊成為JCP的會員后,都可以向JCP提交JSR。比如,你覺得JDK中String的操作方法沒有g(shù)uava中的實用,你提個JSR增強String中的方法,只要能夠通過JCP的審核,就可以在下個版本的JDK中看到了。我們熟知的提案有,Java緩存api的JSR-107、Bean屬性校驗JSR-303等,當(dāng)然還有本篇要講的Java并發(fā)包JSR-166.

JCP官網(wǎng):https://jcp.org

Doug Lea和他的JSR-166

Doug Lea,中文名為道格·利。是美國的一個大學(xué)教師,大神級的人物,J.U.C就是出自他之手。JDK1.5之前,我們控制程序并發(fā)訪問同步代碼只能使用synchronized,那個時候synchronized的性能還沒優(yōu)化好,性能并不好,控制線程也只能使用Object的wait和notify方法。這個時候Doug Lea給JCP提交了JSR-166的提案,在提交JSR-166之前,Doug Lea已經(jīng)使用了類似J.U.C包功能的代碼已經(jīng)三年多了,這些代碼就是J.U.C的原型,下面簡單看下這些具有歷史味道的代碼,同時也能引發(fā)我們的一些思考,如果JDK中沒有,那么就自己造呀!

Lock接口的原型

public class Mutex implements Sync  {
  /** The lock status **/
  protected boolean inuse_ = false;
  @Override
  public void acquire() throws InterruptedException {
    if (Thread.interrupted()) {
      throw new InterruptedException();
    }
    synchronized(this) {
      try {
        //如果inuse_為true就wait住線程
        while (inuse_) {
          wait();
        }
        inuse_ = true;
      }
      catch (InterruptedException ex) {
        notify();
        throw ex;
      }
    }
  }
  /**
   * 釋放鎖,通知線程繼續(xù)執(zhí)行
   */
  @Override
  public synchronized void release()  {
    inuse_ = false;
    notify(); 
  }
  @Override
  public boolean attempt(long msecs) throws InterruptedException {
    if (Thread.interrupted()) {
      throw new InterruptedException();
    }
    synchronized(this) {
      if (!inuse_) {
        inuse_ = true;
        return true;
      }
      else if (msecs <= 0) {
        return false;
      } else {
        long waitTime = msecs;
        long start = System.currentTimeMillis();
        try {
          for (;;) {
            wait(waitTime);
            if (!inuse_) {
              inuse_ = true;
              return true;
            }
            else {
              waitTime = msecs - (System.currentTimeMillis() - start);
              if (waitTime <= 0) 
                return false;
            }
          }
        }
        catch (InterruptedException ex) {
          notify();
          throw ex;
        }
      }
    }  
  }
}

CountDownLatch的原型

public class CountDown implements Sync {
    protected final int initialCount_;
    protected int count_;
    /**
     * Create a new CountDown with given count value
     **/
    public CountDown(int count) {
        count_ = initialCount_ = count;
    }
    @Override
    public void acquire() throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        synchronized (this) {
            while (count_ > 0) {
                wait();
            }
        }
    }
    @Override
    public boolean attempt(long msecs) throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        synchronized (this) {
            if (count_ <= 0) {
                return true;
            } else if (msecs <= 0) {
                return false;
            } else {
                long waitTime = msecs;
                long start = System.currentTimeMillis();
                for (; ; ) {
                    wait(waitTime);
                    if (count_ <= 0) {
                        return true;
                    } else {
                        waitTime = msecs - (System.currentTimeMillis() - start);
                        if (waitTime <= 0) {
                            return false;
                        }
                    }
                }
            }
        }
    }
    /**
     * Decrement the count.
     * After the initialCount'th release, all current and future
     * acquires will pass
     **/
    @Override
    public synchronized void release() {
        if (--count_ == 0) {
            notifyAll();
        }
    }
    /**
     * Return the initial count value
     **/
    public int initialCount() {
        return initialCount_;
    }
    public synchronized int currentCount() {
        return count_;
    }
}

AbstractQueuedSynchronizer抽象類的原型

了解J.U.C的都知道,在這個包里面AbstractQueuedSynchronizer是精髓所在,這就是我們在聊并發(fā)包時俗稱的AQS,這個框架設(shè)計為同步狀態(tài)的原子性管理、線程的阻塞和解除阻塞以及排隊提供一種通用的機制。并發(fā)包下ReentrantLock、CountDownLatch等都是基于AQS來實現(xiàn)的,在看下上面的原型實現(xiàn)都是實現(xiàn)的Sync接口,是不是似曾相識,下面的Sync就是AbstractQueuedSynchronizer的原型了

中文譯文:java并發(fā)包JUC同步器框架AQS框架原文翻譯

public interface Sync {
  public void acquire() throws InterruptedException;
  public boolean attempt(long msecs) throws InterruptedException;
  public void release();
  /**  One second, in milliseconds; convenient as a time-out value **/
  public static final long ONE_SECOND = 1000;
  /**  One minute, in milliseconds; convenient as a time-out value **/
  public static final long ONE_MINUTE = 60 * ONE_SECOND;
  /**  One hour, in milliseconds; convenient as a time-out value **/
  public static final long ONE_HOUR = 60 * ONE_MINUTE;
  /**  One day, in milliseconds; convenient as a time-out value **/
  public static final long ONE_DAY = 24 * ONE_HOUR;
  /**  One week, in milliseconds; convenient as a time-out value **/
  public static final long ONE_WEEK = 7 * ONE_DAY;
  /**  One year in milliseconds; convenient as a time-out value  **/
  public static final long ONE_YEAR = (long)(365.2425 * ONE_DAY);
  /**  One century in milliseconds; convenient as a time-out value **/
  public static final long ONE_CENTURY = 100 * ONE_YEAR;
}

JSR-166的詳細(xì)內(nèi)容

1、請描述擬議的規(guī)范:

這個JSR的目標(biāo)類似于JDK1.2 Collections包的目標(biāo):

  • 1.標(biāo)準(zhǔn)化一個簡單,可擴展的框架,該框架將常用的實用程序組織成一個足夠小的包,以便用戶可以輕松學(xué)習(xí)并由開發(fā)人員維護。
  • 2.提供一些高質(zhì)量的實現(xiàn)。

該包將包含接口和類,這些接口和類在各種編程樣式和應(yīng)用程序中都很有用。這些類包括:

  • 原子變量。
  • 專用鎖,屏障,信號量和條件變量。
  • 為多線程使用而設(shè)計的隊列和相關(guān)集合。
  • 線程池和自定義執(zhí)行框架。

我們還將研究核心語言和庫中的相關(guān)支持。 請注意,這些與J2EE中使用的事務(wù)并發(fā)控制框架完全不同。(但是,對于那些創(chuàng)建此類框架的人來說,它們會很有用。)

2、什么是目標(biāo)Java平臺?

J2SE

3、擬議規(guī)范將解決Java社區(qū)的哪些需求?

底層線程原語(例如synchronized塊,Object.wait和Object.notify)不足以用于許多編程任務(wù)。因此,應(yīng)用程序員經(jīng)常被迫實現(xiàn)自己的更高級別的并發(fā)工具。這導(dǎo)致了巨大的重復(fù)工作。此外,眾所周知,這些設(shè)施難以正確,甚至更難以優(yōu)化。應(yīng)用程序員編寫的并發(fā)工具通常不正確或效率低下。提供一組標(biāo)準(zhǔn)的并發(fā)實用程序?qū)⒑喕帉懜鞣N多線程應(yīng)用程序的任務(wù),并通常可以提高使用它們的應(yīng)用程序的質(zhì)量。

4、為什么現(xiàn)有規(guī)范不滿足這種需求?

目前,開發(fā)人員只能使用Java語言本身提供的并發(fā)控制結(jié)構(gòu)。對于某些應(yīng)用程序來說,這些級別太低,而對其他應(yīng)用程序則不完整

5、請簡要介紹基礎(chǔ)技術(shù)或技術(shù):

絕大多數(shù)軟件包將在低級Java構(gòu)造之上實現(xiàn)。但是,有一些關(guān)于原子性和監(jiān)視器的關(guān)鍵JVM /語言增強功能是獲得高效和正確語義所必需的。

6、API規(guī)范是否有建議的包名?

(即javapi.something,org.something等)

java.util.concurrent中

7、建議的規(guī)范是否與您知道的特定操作系統(tǒng),CPU或I/O設(shè)備有任何依賴關(guān)系?

只是間接地,因為在不同平臺上運行的JVM可能能夠以不同方式優(yōu)化某些構(gòu)造。

8、當(dāng)前的安全模型是否存在無法解決的安全問題?

沒有

9、是否存在國際化或本地化問題?

沒有

10、是否有任何現(xiàn)有規(guī)范可能因此工作而過時,棄用或需要修訂?

沒有

11、請描述制定本規(guī)范的預(yù)期時間表。

目標(biāo)是將此規(guī)范包含在J2SE 1.5(Tiger)的JSR中。

12、請描述致力于制定本規(guī)范的專家組的預(yù)期工作模式。

電子郵件,電話會議和不常見的會議。我們還將使用或創(chuàng)建一個開放的郵件列表,供專家組以外的其他感興趣的人討論。

解密LockSupport和Unsafe

前面說到AQS是并發(fā)包下的精髓所在,那么LockSupport和Unsafe就是整個JSR-166并發(fā)包的所有功能實現(xiàn)的靈魂,縱觀整個并發(fā)包下的代碼,無處不見LockSupport和Unsafe的身影。LockSupport提供了兩個關(guān)鍵方法,park和unpark,用來操作線程的阻塞和放行,功能可以類比Object的wait和notify,但是比這兩個api更靈活。下面是博主簡化了的實現(xiàn)(JDK中不是這樣的)

/**
   用于創(chuàng)建鎖和其他同步類的基本線程阻塞基礎(chǔ)類,提供基礎(chǔ)的線程控制功能。
 */
public class LockSupport {
    private LockSupport() {}
    /**
      解除park的阻塞,如果還沒阻塞,它對{@code park}的下一次調(diào)用將保證不會阻塞
     */
    public static void unpark(Thread thread) {
        if (thread != null) {
            UNSAFE.unpark(thread);
        }
    }
    /**
      阻塞當(dāng)前線程,除非先調(diào)用了unpark()方法。
     */
    public static void park() {
        UNSAFE.park(false, 0L);
    }
    //Hotspot implementation via intrinsics API
    private static final Unsafe UNSAFE;
    static {
        try {
            try {
                final PrivilegedExceptionActionaction = new PrivilegedExceptionAction() {
                    @Override
                    public Unsafe run() throws Exception {
                        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                        theUnsafe.setAccessible(true);
                        return (Unsafe) theUnsafe.get(null);
                    }
                };
                UNSAFE = AccessController.doPrivileged(action);
            } catch (Exception e) {
                throw new RuntimeException("Unable to load unsafe", e);
            }
        } catch (Exception ex) { throw new Error(ex); }
    }
}

有了park和unpark后,我們也可以這樣來實現(xiàn)Lock的功能,代碼如下,有了ConcurrentLinkedQueue加持后,就可以在基本的鎖的功能上,實現(xiàn)公平鎖的語義了。

/**
 * 簡版先進先出的公平鎖實現(xiàn)
 * @author: kl @kailing.pub
 * @date: 2019/9/2
 */
public class FIFOMutex {
    private final AtomicBoolean locked = new AtomicBoolean(false);
    private final Queuewaiters = new ConcurrentLinkedQueue<>();
    public void lock() {
        boolean wasInterrupted = false;
        Thread current = Thread.currentThread();
        waiters.add(current);
        // 在隊列中不是第一個或無法獲取鎖時阻塞
        while (waiters.peek() != current || !locked.compareAndSet(false, true)) {
            LockSupport.park(this);
            if (Thread.interrupted()) {
                wasInterrupted = true;
            }
        }
        waiters.remove();
        if (wasInterrupted) {
            current.interrupt();
        }
    }
    public void unlock() {
        locked.set(false);
        LockSupport.unpark(waiters.peek());
    }
}

神秘的Unsafe,JSR166增加了哪些內(nèi)容

心細(xì)的你可能發(fā)現(xiàn)了LockSupport最終還是基于Unsafe的park和unpark來實現(xiàn)的,Unsafe在JDK1.5之前就存在的,那JSR166后增加了哪些內(nèi)容呢?先來看下Unsafe是什么來頭。JDK源碼中是這樣描述的:一組用于執(zhí)行低層、不安全操作的方法。盡管該類和所有方法都是公共的,但是該類的使用受到限制,因為只有受信任的代碼才能獲得該類的實例。如其名,不安全的,所以在JDK1.8后直接不提供源碼了,JDK中其他的代碼都可以在IDE中直接看到.java的文件,而Unsafe只有.class編譯后的代碼。因為Unsafe是真的有黑魔法,可以直接操作系統(tǒng)級的資源,比如系統(tǒng)內(nèi)存、線程等。JDK不直接對外暴露Unsafe的api,如果直接在自己的應(yīng)用程序中像JDK中那么獲取Unsafe的實例,如:

private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();

會直接拋異常SecurityException("Unsafe"),正確的獲取方式如下:

private static final Unsafe UNSAFE;
    static {
        try {
            try {
                final PrivilegedExceptionActionaction = new PrivilegedExceptionAction() {
                    @Override
                    public Unsafe run() throws Exception {
                        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                        theUnsafe.setAccessible(true);
                        return (Unsafe) theUnsafe.get(null);
                    }
                };
                UNSAFE = AccessController.doPrivileged(action);
            } catch (Exception e) {
                throw new RuntimeException("Unable to load unsafe", e);
            }
        } catch (Exception ex) { throw new Error(ex); }
    }

其實,深入到Unsafe后,會發(fā)現(xiàn)深入不下去了,Unsafe中的方法是都是native標(biāo)記的本地方法,沒有實現(xiàn),如:

public native void unpark(Object var1);

public native void park(boolean var1, long var2);

如果是在Windows下,最終調(diào)用的就是使用C++開發(fā)的最終編譯成.dll的包,所以只要看到C++相關(guān)的代碼就知道怎么回事了

首先定位到Unsafe.cpp,文件位置在:openjdk\hotspot\src\share\vm\prims\Unsafe.cpp,會發(fā)現(xiàn)和JSR166相關(guān)的都有注釋,如:// These are the methods prior to the JSR 166 changes in 1.6.0。根據(jù)這些信息,得知JSR166在Unsafe中新增了五個方法,分別是compareAndSwapObject、compareAndSwapInt、compareAndSwapLong、park、unpark,這就是并發(fā)包中CAS原子操作和線程控制的核心所在了,并發(fā)包中的大部分功能都是基于他們來實現(xiàn)的。最后我們看下park和unpark的具體實現(xiàn),在學(xué)校學(xué)的C語言丟的差不好多了,但是下面的代碼還語義還是很清晰的

// JSR166 // ------------------------------------------------------- /*
 * The Windows implementation of Park is very straightforward: Basic
 * operations on Win32 Events turn out to have the right semantics to
 * use them directly. We opportunistically resuse the event inherited
 * from Monitor.
 *
void Parker::park(bool isAbsolute, jlong time) {
  guarantee (_ParkEvent != NULL, "invariant") ;
  // First, demultiplex/decode time arguments
  if (time < 0) { // don't wait
    return;
  }
  else if (time == 0 && !isAbsolute) {
    time = INFINITE;
  }
  else if  (isAbsolute) {
    time -= os::javaTimeMillis(); // convert to relative time
    if (time <= 0) // already elapsed
      return;
  }
  else { // relative
    time /= 1000000; // Must coarsen from nanos to millis
    if (time == 0)   // Wait for the minimal time unit if zero
      time = 1;
  }
  JavaThread* thread = (JavaThread*)(Thread::current());
  assert(thread->is_Java_thread(), "Must be JavaThread");
  JavaThread *jt = (JavaThread *)thread;
  // Don't wait if interrupted or already triggered
  if (Thread::is_interrupted(thread, false) ||
    WaitForSingleObject(_ParkEvent, 0) == WAIT_OBJECT_0) {
    ResetEvent(_ParkEvent);
    return;
  }
  else {
    ThreadBlockInVM tbivm(jt);
    OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
    jt->set_suspend_equivalent();
    WaitForSingleObject(_ParkEvent,  time);
    ResetEvent(_ParkEvent); // If externally suspended while waiting, re-suspend if (jt->handle_special_suspend_equivalent_condition()) {
      jt->java_suspend_self();
    }
  }
}
void Parker::unpark() {
  guarantee (_ParkEvent != NULL, "invariant") ;
  SetEvent(_ParkEvent);
}

結(jié)語

我們一直受益于J.U.C的代碼,網(wǎng)上也不乏大量的解讀分析J.U.C源碼的文章,但是很少有講J.U.C背后的關(guān)于J.U.C誕生的那些事兒,在深入了解并發(fā)包的代碼同時,發(fā)現(xiàn)了很多值的分享的事情,整個J.U.C的技術(shù)脈絡(luò)也無比的清晰,故記錄下來了。從此,博主在技術(shù)界,又多了一位崇拜的偶像Doug Lea,希望,在讀完本文后也能成為你的偶像。

相關(guān)文章

  • IntelliJ IDEA窗口組件具體操作方法

    IntelliJ IDEA窗口組件具體操作方法

    IDEA剛接觸不久,各種常用工具窗口找不到,不小心關(guān)掉不知道從哪里打開,今天小編給大家分享這個問題的解決方法,感興趣的朋友一起看看吧
    2021-09-09
  • Java虛擬機類加載器之雙親委派機制模型案例

    Java虛擬機類加載器之雙親委派機制模型案例

    這篇文章主要介紹了Java虛擬機類加載器之雙親委派機制模型案例,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • java構(gòu)造方法的作用總結(jié)

    java構(gòu)造方法的作用總結(jié)

    在本篇文章里小編給大家整理了關(guān)于java構(gòu)造方法的相關(guān)知識點以及實例代碼,有需要的朋友們可以學(xué)習(xí)下。
    2019-07-07
  • Java中HashMap與String字符串互轉(zhuǎn)的問題解決

    Java中HashMap與String字符串互轉(zhuǎn)的問題解決

    本文介紹了Java中HashMap與String字符串互轉(zhuǎn)的問題解決,當(dāng)我們有需求將HashMap轉(zhuǎn)為Json格式的String時,需要使用FastJson/Gson將HashMap轉(zhuǎn)為String,感興趣的可以了解一下
    2022-03-03
  • Hibernate的各種保存方式的區(qū)別詳解

    Hibernate的各種保存方式的區(qū)別詳解

    今天小編就為大家分享一篇關(guān)于Hibernate的各種保存方式的區(qū)別詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Java 中Flyway的使用詳解

    Java 中Flyway的使用詳解

    這篇文章主要介紹了Java 中Flyway的使用詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • Java實現(xiàn)簡單的日歷界面

    Java實現(xiàn)簡單的日歷界面

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)簡單的日歷界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • SpringBoot實現(xiàn)redis緩存菜單列表

    SpringBoot實現(xiàn)redis緩存菜單列表

    本文主要介紹了SpringBoot實現(xiàn)redis緩存菜單列表,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java設(shè)計模式之觀察者模式原理與用法詳解

    Java設(shè)計模式之觀察者模式原理與用法詳解

    這篇文章主要介紹了Java設(shè)計模式之觀察者模式,結(jié)合實例形式詳細(xì)分析了Java設(shè)計模式之觀察者模式基本概念、原理、用法及操作注意事項,需要的朋友可以參考下
    2020-06-06
  • 利用Maven添加工程版本信息及時間戳

    利用Maven添加工程版本信息及時間戳

    這篇文章主要介紹了利用Maven添加工程版本信息及時間戳方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評論

朝阳区| 从江县| 黄浦区| 池州市| 新竹县| 松原市| 廉江市| 汉阴县| 深州市| 敦化市| 分宜县| 安乡县| 仙桃市| 仙桃市| 馆陶县| 安宁市| 从化市| 宜黄县| 化德县| 高陵县| 婺源县| 尉犁县| 平泉县| 剑河县| 乌什县| 桐庐县| 井陉县| 文登市| 永寿县| 苏尼特右旗| 元氏县| 仪征市| 江北区| 吉林省| 霞浦县| 江口县| 大荔县| 化州市| 赣州市| 神农架林区| 兴安盟|