ConCurrent in Practice小记 (3)

高级同步技巧

Semaphore

Semaphore信号量,据说是Dijkstra大神发明的。内部维护一个许可集(Permits Set),用于发放许可和回收许可,存在内部计数器,主要用来计数能否得到资源(一般用来限制同时访问资源数)。当一个线程拿到许可,计数器减一;当线程释放资源则计数器加一;当计数器为0则阻塞线程。

特别地: Semaphore的同步锁机制仅仅用于对访问许可的同步,对于需要访问对象的池等的同步锁并不保证。如一个线程池需要访问一个资源池,此时对于每一个需要访问资源的线程,要先获得许可,这是在Semaphore中得到同步保护的,但是在得到许可后,对资源池本身的存取等依然是非同步保护的。需要自己实现。(或者是资源池本身的同步维护)——所以在方法中应该确保首先释放(线程所占)资源,再去释放许可。

JDK中的示例代码:

Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。例如,下面的类使用信号量控制对内容池的访问:
 class Pool {
   private static final int MAX_AVAILABLE = 100;
   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

   public Object getItem() throws InterruptedException {
     available.acquire();
     return getNextAvailableItem();
   }

   public void putItem(Object x) {
     if (markAsUnused(x))
       available.release();
   }

   // Not a particularly efficient data structure; just for demo

   protected Object[] items = ... whatever kinds of items being managed
   protected boolean[] used = new boolean[MAX_AVAILABLE];

   protected synchronized Object getNextAvailableItem() {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (!used[i]) {
          used[i] = true;
          return items[i];
       }
     }
     return null; // not reached
   }

   protected synchronized boolean markAsUnused(Object item) {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (item == items[i]) {
          if (used[i]) {
            used[i] = false;
            return true;
          } else
            return false;
       }
     }
     return false;
   }

 }

Semaphore的构造方法为:
Semaphore(int permits); 给出允许发放的许可个数,默认不公平发放
Semaphore(int permits, boolead fair); 除给出许可个数外,boolean值代表是否允许公平发放许可
acquire(),release()分别是取得许可和释放许可。当Semaphore的许可数目为1时,即只有1和0两种状态,此时的Semaphore被称之为二进制信号量,是完全互斥的,仅允许线程一个一个执行。

另外同Lock类相同,Semaphore也有两种特殊acquire的方法:
acquireUninterruptibly(): 普通的acquire()方法在阻塞的时候是可以被中断的,且抛出异常。但是使用此方法会忽视中断信息且不会抛出异常。
tryAcquire(): 如果可以得到许可返回true,如果不能则立即返回false,并不会阻塞或者等待Semaphore的释放。

CountDownLatch

CountDownLatch提供这样一个类:目的在于同步线程之间的任务,它让一个或多个线程等待,直到一组操作全都执行完毕才返回。初始化时仅需要一个int参数,用来表示这一组操作共有多少任务,该正数传递到CountDownLatch对象的计数器中。当某个线程完成自己的任务时调用await()方法,该方法在内部计数器未自减到0之前让线程保持睡眠,当计数器减少到0时会唤醒所有调用await()而睡眠的线程并返回结果。CountDownLatch对象的countDown()方法会自减其内部计数器。

特别地:注意CountDownLatch对象只能使用一次,内部计数器初始化后均不可再更改值,当计数器减少到0时,再调用countDown()方法也不会有影响。如果需要下一次同步则必须生成新的对象。

CountDownLatch和临界区保护等没有关系,仅

示例代码:

package com.lyb.Section3;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Created by lyb on 15-7-28.
 */
public class VideoConferenceTest {

    public static void main(String[] args){
        VideoConference conference = new VideoConference(10);
        Thread conferenceThread = new Thread(conference);
        conferenceThread.start();

        for (int i = 0; i < 10; i++){
            Participant participant = new Participant(conference,"Participant " + i);
            Thread thread = new Thread(participant);
            thread.start();
        }

    }

}

class VideoConference implements Runnable{

    private final CountDownLatch countDownLatchControler;

    public VideoConference(int number){
        countDownLatchControler = new CountDownLatch(number);
    }

    public void arrive(String name){
        System.out.printf("%s has arrived. \n",name);
        countDownLatchControler.countDown();
        System.out.printf("VideoConference : Waiting for %d conferences \n", countDownLatchControler.getCount());
    }

    public void run(){
        System.out.printf("VideoConference Initialization : %d participants. \n",
                countDownLatchControler.getCount());
        try {
            countDownLatchControler.await();
            System.out.printf("All the participants come \n");
            System.out.printf("Let‘s begin the conference .... \n");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

}

class Participant implements Runnable{

    private VideoConference conference;
    private String name;

    public Participant(VideoConference conference, String name){
        this.conference = conference;
        this.name = name;
    }

    public void run(){
        try {
            long duration = (long)(Math.random()*10);
            TimeUnit.SECONDS.sleep(duration);
        }catch (InterruptedException e ){
            e.printStackTrace();
        }
        conference.arrive(name);
    }

}

CyclicBarrier

CyclicBarrier跟CountDownLatch类相似,也是在多个线程到达某一同步点之后睡眠,等待一系列操作完成之后,再进行下一个任务。这里仍然是同步的线程数目,当有一个线程到达时,先睡眠,到达的数目为制定数目后可以进行初始化参数的Runnable任务。
(这里有一个疑问,如果是线程池中,仅有3条线程,但是在这里CyclicBarrier设置为5,拿是不是永远达不到Barrier了?)

另一个版本的await()方法:
await(long time, TimeUnit unit): 唤醒条件为休眠被中断,内部计数器到达,等待时间到。
getNumberWaiting() 返回当前在屏障前等待的参与者的数目
getParties() 返回同步的任务数,即总共需要达到屏障前的数目

CyclicBarrier同CountDownLatch最大的不同是CyclicBarrier可以被重用,使用reset()方法可以重置barrier,但是全部正在await()的线程将抛出broken异常。Broken状态是Barrier的特殊状态,在此状态下不能操作,状态的引起是由于正在await()的某个线程被中断。isBroken()可以检测该状态。

Phaser

Phaser移相器是JDK1.7引入的新类,可以运行阶段性的并发任务。当任务是分为多个步骤来做,则Phaser可以在每个阶段的的结尾同步线程,所以除非完成第一个阶段,否则不可能开始第二个步骤。

package com.lyb.Section3;

import com.sun.xml.internal.stream.util.ThreadLocalBufferAllocator;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;

/**
 * Created by lyb on 15-7-30.
 */
public class PhaserTest {
    public static void main(String[] args){
        Phaser phaser = new Phaser(3);

        FileSearch ahome = new FileSearch("/home/lyb/WorkSpace","md",phaser);
        FileSearch bhome = new FileSearch("/home/lyb/Book","md",phaser);
        FileSearch chome = new FileSearch("/home/lyb/Software","md",phaser);

        Thread ahomeThread = new Thread(ahome,"WorkSpace");
        ahomeThread.start();

        Thread bhomeThread = new Thread(bhome,"Book");
        bhomeThread.start();

        Thread chomeThread = new Thread(chome,"Software");
        chomeThread.start();

        try {
            ahomeThread.join();
            bhomeThread.join();
            chomeThread.join();
        }catch (InterruptedException e){
            e.printStackTrace();
        }

        System.out.printf("Terminated:" + phaser.isTerminated());
    }

}

class FileSearch implements Runnable{
    private String initPath;
    private String end;
    private Phaser phaser;
    private List<String> results;

    public FileSearch(String initPath, String end, Phaser phaser){
        this.initPath = initPath;
        this.end = end;
        this.phaser = phaser;
        results = new ArrayList<>();
    }

    private void directoryProcessed(File file){
        File filelist[] = file.listFiles();
        if (filelist != null){
            for (File file1 : filelist){
                if (file1.isDirectory()){
                    directoryProcessed(file1);
                }else {
                    fileProcessed(file1);
                }
            }
        }
    }

    private void fileProcessed(File file){
        if (file.getName().endsWith(end)){
            results.add(file.getAbsolutePath());
        }
    }

    private void filterResults(){
        List<String> newResults = new ArrayList<>();
        long actualTime = new Date().getTime();
        for (String filePath : results){
            File file = new File(filePath);
            long modifyTime = file.lastModified();
            if (actualTime - modifyTime < TimeUnit.MILLISECONDS.convert(100,TimeUnit.DAYS)){
                newResults.add(filePath);
            }
        }
        results = newResults;
    }

    private boolean checkResults(){
        if (results.isEmpty()){
            System.out.printf("%s : Phase %d: 0 results \n",
                    Thread.currentThread().getName(),
                    phaser.getPhase());
            System.out.printf("%s : Phase %d: end \n",
                    Thread.currentThread().getName(),
                    phaser.getPhase());
            phaser.arriveAndDeregister();
            return false;
        }else {
            System.out.printf("%s : Phase %d : %d results. \n",
                    Thread.currentThread().getName(),
                    phaser.getPhase(),results.size());
            phaser.arriveAndAwaitAdvance();
            return true;
        }
    }

    private void showInfo(){
        for (String filePath : results){
            File file = new File(filePath);
            System.out.printf("%s : %s \n",Thread.currentThread().getName(),file.getAbsoluteFile());
        }
        phaser.arriveAndAwaitAdvance();
    }

    public void run(){
        phaser.arriveAndAwaitAdvance();
        System.out.printf("%s Starting. \n", Thread.currentThread().getName());
        File file = new File(initPath);
        if (file.isDirectory()){
            directoryProcessed(file);
        }

        if (!checkResults()){
            return;
        }

        filterResults();
        if (!checkResults()){
            return;
        }

        showInfo();
        phaser.arriveAndDeregister();
        System.out.printf("%s Work completed. \n", Thread.currentThread().getName());
    }

}

Phaser的构造函数接受的参数是指在phase末端控制的同步的线程数目,也称之为参与者数目。在run方法中首先调用arriveAndAwaitAdvance(),这样每个线程都在自己创建完毕后等待其他线程,同时每次调用该方法,会更新phase内部的线程计数,减去完结的线程数,得到现在实际应该同步的线程数,并使当前线程睡眠,等待最后一个同步线程到达,使所有的线程唤醒,开始执行第二个phase的操作。

arriveAndDeregister()是在线程到达phase时,已经判定为应该终止的线程,Deregister之后,phase内部计数减一,不会再计算该线程。当然每个phase执行到最后,都应每个线程调用该方法,退出phase计数。

最终,由main方法中调用isTerminated()退出phaser。

Phaser 对象可能是在这2中状态:

  • Active: 当 Phaser 接受新的参与者注册,它进入这个状态,并且在每个phase的末端同步。 (在此状态,Phaser像在这个指南里解释的那样工作。此状态不在Java 并发 API中。)
  • Termination: 默认状态,当Phaser里全部的参与者都取消注册,它进入这个状态,所以这时 Phaser 有0个参与者。更具体的说,当onAdvance() 方法返回真值时,Phaser 是在这个状态里。如果你覆盖那个方法,你可以改变它的默认行为。当 Phaser 在这个状态,同步方法 arriveAndAwaitAdvance()会立刻返回,不会做任何同步。

Phaser 类的一个显著特点是你不需要控制任何与phaser相关的方法的异常。不像其他同步应用,线程们在phaser休眠不会响应任何中断也不会抛出 InterruptedException 异常。只有一个异常InterruptedException在特定中才会出现。

The Phaser类还提供了其他相关方法来改变phase。他们是:

  • arrive(): 此方法示意phaser某个参与者已经结束actual phase了,但是他应该等待其他的参与者才能继续执行。小心使用此法,因为它并不能与其他线程同步。(不懂。。。)
  • awaitAdvance(int phase): 如果我们传递的参数值等于phaser的actual phase,此方法让当前线程进入睡眠直到phaser的全部参与者结束当前的phase。如果参数值与phaser 的 actual phase不等,那么立刻返回。
  • awaitAdvanceInterruptibly(int phaser): 此方法等同与之前的方法,只是在线程正在此方法中休眠而被中断时候,它会抛出InterruptedException 异常。

当你创建一个 Phaser 对象,你表明了参与者的数量。但是Phaser类还有2种方法来增加参与者的数量。他们是:

  • register(): 此方法为Phaser添加一个新的参与者。这个新加入者会被认为是还未到达 actual phase.
  • bulkRegister(int Parties): 此方法为Phaser添加一个特定数量的参与者。这些新加入的参与都会被认为是还未到达 actual phase.
  • Phaser类提供的唯一一个减少参与者数量的方法是arriveAndDeregister() 方法,它通知phaser线程已经结束了actual phase,而且他不想继续phased的操作了。

当phaser有0个参与者,它进入一个称为Termination的状态。Phaser 类提供 forceTermination() 来改变phaser的状态,让它直接进入Termination 状态,不在乎已经在phaser中注册的参与者的数量。此机制可能会很有用在一个参与者出现异常的情况下来强制结束phaser.

当phaser在 Termination 状态, awaitAdvance() 和 arriveAndAwaitAdvance() 方法立刻返回一个负值,而不是一般情况下的正值如果你知道你的phaser可能终止了,那么你可以用这些方法来确认他是否真的终止了。

个人总结:

  1. 任意时刻都可以加入phase,通过register和bulkregister,第一次到达phase才开始同步
  2. onArrive和onAdvance会手动调用线程的到达,onarrive并不等待其他的线程,而如果onAdvance返回true(其实是判断内部的计数是否是0),则即将进入termination。
  3. 可以级联,成为phase树,而且child phase的参与者的register是自动在parent的计数上注册的。当子phase参与者为0,则自动从树上裂解。
  4. 有效的镜像,可以通过随时调用getxxx方法得到参与者数量,为到达数量等等。

generated by haroopad

:first-child{margin-top:0!important}img.plugin{box-shadow:0 1px 3px rgba(0,0,0,.1);border-radius:3px}iframe{border:0}figure{-webkit-margin-before:0;-webkit-margin-after:0;-webkit-margin-start:0;-webkit-margin-end:0}kbd{border:1px solid #aaa;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-moz-box-shadow:1px 2px 2px #ddd;-webkit-box-shadow:1px 2px 2px #ddd;box-shadow:1px 2px 2px #ddd;background-color:#f9f9f9;background-image:-moz-linear-gradient(top,#eee,#f9f9f9,#eee);background-image:-o-linear-gradient(top,#eee,#f9f9f9,#eee);background-image:-webkit-linear-gradient(top,#eee,#f9f9f9,#eee);background-image:linear-gradient(top,#eee,#f9f9f9,#eee);padding:1px 3px;font-family:inherit;font-size:.85em}.oembeded .oembed_photo{display:inline-block}img[data-echo]{margin:25px 0;width:100px;height:100px;background:url(../img/ajax.gif) center center no-repeat #fff}.spinner{display:inline-block;width:10px;height:10px;margin-bottom:-.1em;border:2px solid rgba(0,0,0,.5);border-top-color:transparent;border-radius:100%;-webkit-animation:spin 1s infinite linear;animation:spin 1s infinite linear}.spinner:after{content:‘‘;display:block;width:0;height:0;position:absolute;top:-6px;left:0;border:4px solid transparent;border-bottom-color:rgba(0,0,0,.5);-webkit-transform:rotate(45deg);transform:rotate(45deg)}@-webkit-keyframes spin{to{-webkit-transform:rotate(360deg)}}@keyframes spin{to{transform:rotate(360deg)}}p.toc{margin:0!important}p.toc ul{padding-left:10px}p.toc>ul{padding:10px;margin:0 10px;display:inline-block;border:1px solid #ededed;border-radius:5px}p.toc li,p.toc ul{list-style-type:none}p.toc li{width:100%;padding:0;overflow:hidden}p.toc li a::after{content:"."}p.toc li a:before{content:"? "}p.toc h5{text-transform:uppercase}p.toc .title{float:left;padding-right:3px}p.toc .number{margin:0;float:right;padding-left:3px;background:#fff;display:none}input.task-list-item{margin-left:-1.62em}.markdown{font-family:"Hiragino Sans GB","Microsoft YaHei",STHeiti,SimSun,"Lucida Grande","Lucida Sans Unicode","Lucida Sans",‘Segoe UI‘,AppleSDGothicNeo-Medium,‘Malgun Gothic‘,Verdana,Tahoma,sans-serif;padding:20px}.markdown a{text-decoration:none;vertical-align:baseline}.markdown a:hover{text-decoration:underline}.markdown h1{font-size:2.2em;font-weight:700;margin:1.5em 0 1em}.markdown h2{font-size:1.8em;font-weight:700;margin:1.275em 0 .85em}.markdown h3{font-size:1.6em;font-weight:700;margin:1.125em 0 .75em}.markdown h4{font-size:1.4em;font-weight:700;margin:.99em 0 .66em}.markdown h5{font-size:1.2em;font-weight:700;margin:.855em 0 .57em}.markdown h6{font-size:1em;font-weight:700;margin:.75em 0 .5em}.markdown h1+p,.markdown h1:first-child,.markdown h2+p,.markdown h2:first-child,.markdown h3+p,.markdown h3:first-child,.markdown h4+p,.markdown h4:first-child,.markdown h5+p,.markdown h5:first-child,.markdown h6+p,.markdown h6:first-child{margin-top:0}.markdown hr{border:1px solid #ccc}.markdown p{margin:1em 0;word-wrap:break-word}.markdown ol{list-style-type:decimal}.markdown li{display:list-item;line-height:1.4em}.markdown blockquote{margin:1em 20px}.markdown blockquote>:first-child{margin-top:0}.markdown blockquote>:last-child{margin-bottom:0}.markdown blockquote cite:before{content:‘\2014 \00A0‘}.markdown .code{border-radius:3px;word-wrap:break-word}.markdown pre{border-radius:3px;word-wrap:break-word;border:1px solid #ccc;overflow:auto;padding:.5em}.markdown pre code{border:0;display:block}.markdown pre>code{font-family:Consolas,Inconsolata,Courier,monospace;font-weight:700;white-space:pre;margin:0}.markdown code{border-radius:3px;word-wrap:break-word;border:1px solid #ccc;padding:0 5px;margin:0 2px}.markdown img{max-width:100%}.markdown mark{color:#000;background-color:#fcf8e3}.markdown table{padding:0;border-collapse:collapse;border-spacing:0;margin-bottom:16px}.markdown table tr td,.markdown table tr th{border:1px solid #ccc;margin:0;padding:6px 13px}.markdown table tr th{font-weight:700}.markdown table tr th>:first-child{margin-top:0}.markdown table tr th>:last-child{margin-bottom:0}.markdown table tr td>:first-child{margin-top:0}.markdown table tr td>:last-child{margin-bottom:0}.github{padding:20px;font-family:"Helvetica Neue",Helvetica,"Hiragino Sans GB","Microsoft YaHei",STHeiti,SimSun,"Segoe UI",AppleSDGothicNeo-Medium,‘Malgun Gothic‘,Arial,freesans,sans-serif;font-size:15px;background:#fff;line-height:1.6;-webkit-font-smoothing:antialiased}.github a{color:#3269a0}.github a:hover{color:#4183c4}.github h2{border-bottom:1px solid #e6e6e6;line-height:1.6}.github h6{color:#777}.github hr{border:1px solid #e6e6e6}.github pre>code{font-size:.9em;font-family:Consolas,Inconsolata,Courier,monospace}.github blockquote>code,.github h1>code,.github h2>code,.github h3>code,.github h4>code,.github h5>code,.github h6>code,.github li>code,.github p>code,.github td>code{background-color:rgba(0,0,0,.07);font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:85%;padding:.2em .5em;border:0}.github blockquote{border-left:4px solid #e6e6e6;padding:0 15px;font-style:italic}.github table{background-color:#fafafa}.github table tr td,.github table tr th{border:1px solid #e6e6e6}.github table tr:nth-child(2n){background-color:#f2f2f2}.hljs{display:block;overflow-x:auto;padding:.5em;color:#333;background:#f8f8f8;-webkit-text-size-adjust:none}.diff .hljs-header,.hljs-comment,.hljs-javadoc{color:#998;font-style:italic}.css .rule .hljs-keyword,.hljs-keyword,.hljs-request,.hljs-status,.hljs-subst,.hljs-winutils,.nginx .hljs-title{color:#333;font-weight:700}.hljs-hexcolor,.hljs-number,.ruby .hljs-constant{color:teal}.hljs-dartdoc,.hljs-phpdoc,.hljs-string,.hljs-tag .hljs-value,.tex .hljs-formula{color:#d14}.hljs-id,.hljs-title,.scss .hljs-preprocessor{color:#900;font-weight:700}.hljs-list .hljs-keyword,.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type,.tex .hljs-command,.vhdl .hljs-literal{color:#458;font-weight:700}.django .hljs-tag .hljs-keyword,.hljs-rules .hljs-property,.hljs-tag,.hljs-tag .hljs-title{color:navy;font-weight:400}.hljs-attribute,.hljs-variable,.lisp .hljs-body{color:teal}.hljs-regexp{color:#009926}.clojure .hljs-keyword,.hljs-prompt,.hljs-symbol,.lisp .hljs-keyword,.ruby .hljs-symbol .hljs-string,.scheme .hljs-keyword,.tex .hljs-special{color:#990073}.hljs-built_in{color:#0086b3}.hljs-cdata,.hljs-doctype,.hljs-pi,.hljs-pragma,.hljs-preprocessor,.hljs-shebang{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.diff .hljs-change{background:#0086b3}.hljs-chunk{color:#aaa}.MathJax_Hover_Frame{border-radius:.25em;-webkit-border-radius:.25em;-moz-border-radius:.25em;-khtml-border-radius:.25em;box-shadow:0 0 15px #83A;-webkit-box-shadow:0 0 15px #83A;-moz-box-shadow:0 0 15px #83A;-khtml-box-shadow:0 0 15px #83A;border:1px solid #A6D!important;display:inline-block;position:absolute}.MathJax_Hover_Arrow{position:absolute;width:15px;height:11px;cursor:pointer}#MathJax_About{position:fixed;left:50%;width:auto;text-align:center;border:3px outset;padding:1em 2em;background-color:#DDD;color:#000;cursor:default;font-family:message-box;font-size:120%;font-style:normal;text-indent:0;text-transform:none;line-height:normal;letter-spacing:normal;word-spacing:normal;word-wrap:normal;white-space:nowrap;float:none;z-index:201;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;-khtml-border-radius:15px;box-shadow:0 10px 20px gray;-webkit-box-shadow:0 10px 20px gray;-moz-box-shadow:0 10px 20px gray;-khtml-box-shadow:0 10px 20px gray;filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color=‘gray‘, Positive=‘true‘)}.MathJax_Menu{position:absolute;background-color:#fff;color:#000;width:auto;padding:5px 0;border:1px solid #CCC;margin:0;cursor:default;font:menu;text-align:left;text-indent:0;text-transform:none;line-height:normal;letter-spacing:normal;word-spacing:normal;word-wrap:normal;white-space:nowrap;float:none;z-index:201;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;-khtml-border-radius:5px;box-shadow:0 10px 20px gray;-webkit-box-shadow:0 10px 20px gray;-moz-box-shadow:0 10px 20px gray;-khtml-box-shadow:0 10px 20px gray;filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color=‘gray‘, Positive=‘true‘)}.MathJax_MenuItem{padding:1px 2em;background:0 0}.MathJax_MenuArrow{position:absolute;right:.5em;color:#666}.MathJax_MenuActive .MathJax_MenuArrow{color:#fff}.MathJax_MenuArrow.RTL{left:.5em;right:auto}.MathJax_MenuCheck{position:absolute;left:.7em}.MathJax_MenuCheck.RTL{right:.7em;left:auto}.MathJax_MenuRadioCheck{position:absolute;left:.7em}.MathJax_MenuRadioCheck.RTL{right:.7em;left:auto}.MathJax_MenuLabel{padding:1px 2em 3px 1.33em;font-style:italic}.MathJax_MenuRule{border-top:1px solid #DDD;margin:4px 3px}.MathJax_MenuDisabled{color:GrayText}.MathJax_MenuActive{background-color:#606872;color:#fff}.MathJax_Menu_Close{position:absolute;width:31px;height:31px;top:-15px;left:-15px}#MathJax_Zoom{position:absolute;background-color:#F0F0F0;overflow:auto;display:block;z-index:301;padding:.5em;border:1px solid #000;margin:0;font-weight:400;font-style:normal;text-align:left;text-indent:0;text-transform:none;line-height:normal;letter-spacing:normal;word-spacing:normal;word-wrap:normal;white-space:nowrap;float:none;box-shadow:5px 5px 15px #AAA;-webkit-box-shadow:5px 5px 15px #AAA;-moz-box-shadow:5px 5px 15px #AAA;-khtml-box-shadow:5px 5px 15px #AAA;filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color=‘gray‘, Positive=‘true‘)}#MathJax_ZoomOverlay{position:absolute;left:0;top:0;z-index:300;display:inline-block;width:100%;height:100%;border:0;padding:0;margin:0;background-color:#fff;opacity:0;filter:alpha(opacity=0)}#MathJax_ZoomFrame{position:relative;display:inline-block;height:0;width:0}#MathJax_ZoomEventTrap{position:absolute;left:0;top:0;z-index:302;display:inline-block;border:0;padding:0;margin:0;background-color:#fff;opacity:0;filter:alpha(opacity=0)}.MathJax_Preview{color:#888}#MathJax_Message{position:fixed;left:1px;bottom:2px;background-color:#E6E6E6;border:1px solid #959595;margin:0;padding:2px 8px;z-index:102;color:#000;font-size:80%;width:auto;white-space:nowrap}#MathJax_MSIE_Frame{position:absolute;top:0;left:0;width:0;z-index:101;border:0;margin:0;padding:0}.MathJax_Error{color:#C00;font-style:italic}footer{position:fixed;font-size:.8em;text-align:right;bottom:0;margin-left:-25px;height:20px;width:100%}
-->

时间: 2024-10-17 05:55:42

ConCurrent in Practice小记 (3)的相关文章

ConCurrent in Practice小记 (2)

Java-ConCurrent2.html :first-child{margin-top:0!important}img.plugin{box-shadow:0 1px 3px rgba(0,0,0,.1);border-radius:3px}iframe{border:0}figure{-webkit-margin-before:0;-webkit-margin-after:0;-webkit-margin-start:0;-webkit-margin-end:0}kbd{border:1p

并发理解(阻塞队列)

一.java中阻塞队列如何设计 关于java中的阻塞队列 队列非常适合于生产者/消费者这种业务场景,像rabbitMq,activeMq都是对queue的一个封装的中间件. java中提供了阻塞队列的实现. Queue是接口,定义了存取这些基本接口: public interface Queue<E> extends Collection<E> { //放入到队列,如果放不进则抛错,成功返回true boolean add(E e); //放入queue,返回成功或失败 boole

用happen-before规则重新审视DCL(转)

1.http://www.iteye.com/topic/260515 编写Java多线程程序一直以来都是一件十分困难的事,多线程程序的bug很难测试,DCL(Double Check Lock)就是一个典型,因此对多线程安全的理论分析就显得十分重要,当然这决不是说对多线程程序的测试就是不必要的.传统上,对多线程程序的分析是通过分析操作之间可能的执行先后顺序,然而程序执行顺序十分复杂,它与硬件系统架构,编译器,缓存以及虚拟机的实现都有着很大的关系.仅仅为了分析多线程程序就需要了解这么多底层知识确

Java-SynchronousQueue 阻塞队列小记

在BlockingQueue的子类中有一个SynchronousQueue(同步队列)比较少见,现在做一个简单的介绍,并附加一个简单的例子. SynchronousQueue --JDK1.6介绍: public class SynchronousQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable 一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作 ,反之亦然

Java Concurrency In Practice -Chapter 2 Thread Safety

Writing thread-safe code is managing access to state and in particular to shared, mutable state. Object's state is its data, stored in state variables such as instance or static fields. Whether an object needs to be thread-safe depends on whether it

Architectures for concurrent graphics processing operations

BACKGROUND 1. Field The present invention generally relates to rendering two-dimension representations from three-dimensional scenes, and more particularly to using ray tracing for accelerated rendering of photo-realistic two-dimensional representati

Java并发编程:Concurrent锁机制解析

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

SpringBoot - 二零一七0421小记

一.SpringBoot使用起来比起SpringMVC更便捷,在注解上的小变化,我记录了下面几个: @Controller + @ResponseBody = SpringMVC中用@RestController来代替前面两个注解,通过这个注解,可以将所有的前端http请求放入SpringBoot的Controller容器中,并返回json格式的数据给前端 @RequestMapping(value={"/hello","/hi"},method=RequestMe

hdu 1094 A+B for Input-Output Practice (VI)

A+B for Input-Output Practice (VI) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 63087    Accepted Submission(s): 42387 Problem Description Your task is to calculate the sum of some integers.