Concurrent包工具类使用

一。读写锁java

  传统的同步锁就是独占式锁,当线程使用资源时候保持独占,不管读写。当人们发现请求队列(假设)中相邻请求为读-读的时候,阻塞是一种浪费资源的操做。好比公告板,全部路过的人(请求)都是读操做,并无由于你和他在读的时候对内容形成了改变,因此在模型中,读与读操做不须要阻塞。而读写相邻则须要进行独占式操做了,由于写未完成的时候,信息是不完整的,此时读出来的信息有多是错误的,因此写必然要保持独占式操做。而在应用程序中,读的频率是写的好几倍,也就是说若是读-读是不阻塞的,那么对性能来讲是毋庸置疑的提高。多线程

  Java中存在一种锁,名曰:ReentrantReadWriteLock。他能够实现内存中对资源操做的读写锁,读与读是不阻塞的。并发

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by MacBook on 2018/3/10.
 */
public class ReadWriteLockDemo {
    private static Lock relock = new ReentrantLock();
    private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private static Lock readLock = readWriteLock.readLock();
    private static Lock writeLock = readWriteLock.writeLock();
    private int value;
    public Object handleRead(Lock lock) throws Exception{
        try{
            lock.lock();
            Thread.sleep(1000);
            return value;
        }finally {
            lock.unlock();
        }
    }
    public void handleWrite(Lock lock,int index) throws Exception{
        try{
            lock.lock();
            Thread.sleep(1000);
            value = index;
        }finally {
            lock.unlock();
        }
    }
    public static void main(String[] args){
        ReadWriteLockDemo demo = new ReadWriteLockDemo();
        Runnable readThread = new Runnable() {
            @Override
            public void run() {
                try{
                    System.out.println("read:"+demo.handleRead(readLock));
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        };
        Runnable writeThread = new Runnable() {
            @Override
            public void run() {
                try{
//                    demo.handleWrite(relock,new Random().nextInt());
                    demo.handleWrite(writeLock,new Random().nextInt());
                    System.out.println("id:"+Thread.currentThread().getId()+" done!");
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        };
        for(int i=0;i<18;i++){
            new Thread(readThread).start();
        }
        for(int i=0;i<18;i++){
            new Thread(writeThread).start();
        }
    }

}

    此demo使用了重入锁和读写锁的对比,在主程序中分别新建18个读写操做,若是使用了读操做,则打印的读操做是连续的;若是使用了重入锁,则可能的状况是读写相邻打印,而且都是阻塞的,读者能够自行测试体会。dom

二。对象监视器Conditionide

  在JDK实现了Lock来简化synchronized以后,Condition做为简化监视器而存在。Condition的await方法和signal方法对应对象的wait和signal。高并发

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by MacBook on 2018/3/10.
 */
public class ConditionAndLock implements Runnable{
    static ReentrantLock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();

    public void run(){
        try{
            lock.lock();
            condition.await();
            System.out.println("thread is running");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public static void main(String[] args){
        ConditionAndLock c = new ConditionAndLock();
        Thread t = new Thread(c);
        t.start();
        lock.lock();
        System.out.println("signal all");
        condition.signalAll();
        lock.unlock();
    }
}

三。倒计时器CountDownLatch性能

  多线程中,须要知道这批线程的最大完成任务时间,也就是从第一个任务开始到最后返回这段时间的时长,那么倒计时器是必不可少的。就像各项资源准备完毕才进行下一步操做的模型同样,CountDownLatch就是这样的多线程模型。等到全部任务调用了计数器,而且计数器总数到达某个数量时候,它才会将阻塞代码放开,让主线程往下走。测试

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 倒计时器
 * Created by MacBook on 2018/3/10.
 */
public class CountDownLatchDemo implements Runnable{
    static CountDownLatch end = new CountDownLatch(10);
    static CountDownLatchDemo demo = new CountDownLatchDemo();
    public void run(){
        try{
            Thread.sleep(new Random().nextInt(10)*1000);
            System.out.println(Thread.currentThread().getId()+" check complete!");
            end.countDown();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception{
        ExecutorService service = Executors.newFixedThreadPool(10);
        for(int i=0;i<10;i++){
            service.submit(demo);
        }
        end.await();
        System.out.println("fire");
        service.shutdown();
    }
}

    await方法是阻塞倒计时器所在线程的方法,等到线程池service中调用countDown方法到达必定的数量(此处是10)以后,主线程的await方法才会过去。ui

四。信号量this

  信号量这个东西就比较玄乎了,有点像准入许可,拿到信号准入的时候才往下执行。就像是有一批人拿号,只有号码区间在某个范围的人能进去办事,而后办完事就会让资源释放,号码区间日后移。然而在信号量中应该算是复用类型的,归还了key值,将key值返回给下一个申请者。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * Created by MacBook on 2018/3/10.
 */
public class SemapDemo implements Runnable{
    final Semaphore semp = new Semaphore(5);
    public void run(){
        try{
            semp.acquire();
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getId()+" done!");
            semp.release();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        SemapDemo semapDemo = new SemapDemo();
        for(int i=0;i<20;i++){
            executorService.submit(semapDemo);
        }
        executorService.shutdown();
    }
}

  在acquire得到key以后,操做读写,以后release。

五。栅栏

  栅栏和倒计时器很像,就是拦住一堆线程,等到线程数达到某个设定值以后同时把它们放出去。可是不一样的是,它能够每次设定值达成时候运行定制线程中的run方法。就像是每次一个栏,够数就放。

import java.util.Random;
import java.util.concurrent.CyclicBarrier;

/**
 * Created by MacBook on 2018/3/10.
 */
public class CylicBarrierDemo {
    public static class Soldier implements Runnable{
        private String soldier;
        private final CyclicBarrier cyclicBarrier;
        Soldier(String soldier,CyclicBarrier cyclicBarrier){
            this.soldier = soldier;
            this.cyclicBarrier = cyclicBarrier;
        }
        public void run(){
            try{
                cyclicBarrier.await();
                doWork();
                cyclicBarrier.await();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        public void doWork(){
            try{
                Thread.sleep(Math.abs(new Random().nextInt()%10000));
            }catch (Exception e){
                e.printStackTrace();
            }
            System.out.println(soldier + " done!");
        }
    }
    public static class BarrierRun implements Runnable{
        boolean flag;
        int n;
        public BarrierRun(boolean flag,int n){
            this.flag = flag;
            this.n = n;
        }

        public void run(){
            if(flag){
                System.out.println("士兵:"+n+"个 done!");
            }else {
                System.out.println("士兵:"+n+"个 集合完毕!");
                flag = true;
            }
        }
    }
    public static void main(String[] args){
        final int n = 10;
        Thread[] allSoldier = new Thread[n];
        boolean flag = false;
        CyclicBarrier cyclic = new CyclicBarrier(n,new BarrierRun(flag,n));
        System.out.println("集合");
        for(int i =0; i < n ; i++){
            System.out.println("士兵 "+i+" 报道");
            allSoldier[i] = new Thread(new Soldier("士兵"+i,cyclic));
            allSoldier[i].start();
        }
    }
}

  例中CyclicBarrier有两个参数,前一个就是提到的设定值,后一个就是定制线程了。每当到达设定值的时候会触发定制线程。

  每一个阶段完成都会调用一下定制线程。

六。LockSupport提供线程挂起操做的支持类

  正如Condition使得原有的Object监视器封装成了新类,LockSupport提供使线程park和unpark之类的操做。

import java.util.concurrent.locks.LockSupport;

/**
 * Created by MacBook on 2018/3/10.
 */
public class LockSupportDemo {
    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);
        }
        public void run(){
            synchronized (u){
                System.out.println("in "+getName());
                LockSupport.park();
            }
        }
    }
    public static void main(String[] args) throws Exception{
        t1.start();
        Thread.sleep(100);
        t2.start();
        LockSupport.unpark(t1);
        LockSupport.unpark(t2);
        t1.join();
        t2.join();
    }

}

  它在park时候线程会变成wait状态,而不是runnable。

 

  来自《Java高并发程序设计》的读书笔记

相关文章
相关标签/搜索