学习笔记 1.高性能编程 1.3.4J.U.C并发编程工具包

CountDownLatch

它允许多个线程等待直到在其他线程中一组操作执行完成
CountDownLatch初始化的时候需要传入参数N
await()方法能够阻塞线程直到调用N次的countDown()后才会释放线程
countDown()可以在多个线程中调用,每次调用N减一
可以将CountDownLatch理解为一种特殊的共享锁,每次countDown()后会释放锁,当所有的线程释放完锁后,执行await()方法的线程,会抢占此锁。

public class Test_CountDownLatch {

    /*
    没隔1s开启一个线程,共开启6个线程
    若希望6个线程 同时 执行某一操作
    可以用CountDownLatch实现
     */
    public static void test01() throws InterruptedException {
        CountDownLatch ctl = new CountDownLatch(6);

        for (int i=0; i<6; i++) {
            new Thread() {
                @Override
                public void run() {
                    ctl.countDown();
                    try {
                        ctl.await();
                        System.out.println("here i am..");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
            Thread.sleep(1000);
        }
    }

    /*
    开启6个线程,main线程希望6个线程都执行完某个操作后,才执行某个操作
    可以用CountDownLatch来实现
     */
    public static void test02() throws InterruptedException {
         CountDownLatch ctl = new CountDownLatch(6);
         for (int i = 0; i<6 ; i++) {
             new Thread() {
                 @Override
                 public void run() {
                     System.out.println("after print..");
                     ctl.countDown();
                 }
             }.start();
             Thread.sleep(1000);
         }
         ctl.await();
         System.out.println("main thread do something ...");
    }

    public static void main(String args[]) throws InterruptedException {
        test01();
    }
}

手写一个简单的CountDownLatch类

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class TomCountDownlatch {
    private Sync sync;

    public TomCountDownlatch(int count) {
        sync = new Sync(count);
    }

    public void countDown() {
        sync.releaseShared(1);
    }

    public void await() {
        sync.acquireShared(1);
    }


    class Sync extends AbstractQueuedSynchronizer {
        public Sync(int count) {
            setState(count);
        }

        @Override
        protected int tryAcquireShared(int arg) {
            //当state变为0的时候,加锁成功
            return getState()==0 ? 1:-1;
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            for (;;){
                int c = getState();
                if (c == 0 ){
                    return false;
                }
                int nextc = c-1;
                if (compareAndSetState(c,nextc)) {
                    return nextc == 0;
                }
            }
        }
    }
}

Semaphore

Semaphore是一个计数信号量,常用于限制可以访问某些资源(物理或者逻辑的)线程数目
简单来说是一种控制并发量的共享锁
应用场景:数据库限流等

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class TomCountDownlatch {
    private Sync sync;

    public TomCountDownlatch(int count) {
        sync = new Sync(count);
    }

    public void countDown() {
        sync.releaseShared(1);
    }

    public void await() {
        sync.acquireShared(1);
    }


    class Sync extends AbstractQueuedSynchronizer {
        public Sync(int count) {
            setState(count);
        }

        @Override
        protected int tryAcquireShared(int arg) {
            //当state变为0的时候,加锁成功
            return getState()==0 ? 1:-1;
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            for (;;){
                int c = getState();
                if (c == 0 ){
                    return false;
                }
                int nextc = c-1;
                if (compareAndSetState(c,nextc)) {
                    return nextc == 0;
                }
            }
        }
    }
}
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class TomSemaphore {

    private Sync sync;

    public TomSemaphore(int permits) {
        sync = new Sync(permits);
    }

    public void acquire() {
        sync.acquireShared(1);
    }

    public void release() {
        sync.releaseShared(1);
    }

    class Sync extends AbstractQueuedSynchronizer {
        int permits;

        public Sync(int permits) {
            this.permits = permits;
        }


        //加锁
        @Override
        protected int tryAcquireShared(int arg) {
            int state = getState();
            int nextState = state + arg;
            //如果信号量没占满,加锁的个数没有达到permits
            if (nextState <= permits){
                if (compareAndSetState(state, nextState))
                    return 1;
            }
            return -1;
        }

        //解锁
        @Override
        protected boolean tryReleaseShared(int arg) {
            int state = getState();
            if (compareAndSetState(state,state-arg)){
                return false;
            } else {
                return true;
            }
        }
    }
}

CyclicBarrier

循环栅栏,可以循环利用的屏障。
举例:排队上摩天轮,每到齐四个人,就可以上同一车厢。
简单使用:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.locks.LockSupport;

public class Test_CyclicBarrier {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(4,
                new Thread(){
                    @Override
                    public void run() {
                        System.out.println("==========>>>>>>>>>栅栏");
                    }
                });

        for (int i=0; i<100; i++) {
            new Thread() {
                @Override
                public void run() {
                    try {
                        barrier.await();
                        System.out.println("上到摩天轮");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
            LockSupport.parkNanos(1000 * 1000 * 10000);
        }
    }
}

原理解析:使用可重入锁将其挂起,并使用全局分代和局部分代进行对比来确认批次从而完成唤醒操作。

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

public class TomCyclicBarrier {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    //记录当前这个批次有多少个
    private int count = 0;

    //记录批次大小
    private final int parties;

    //分代
    private Object generation = new Object();

    public TomCyclicBarrier(int parties) {
        if (parties <= 0)  {
            throw new IllegalArgumentException();
        }
        this.parties = parties;
    }

    //进入下一个分代
    public void nextGeneration() {
        condition.signalAll();
        count = 0;
        generation = new Object();
    }

    public void await() {
        //时间排队,需要将线程放入等待队列
        //还需要将线程挂起
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //记录当前的generation,相当于记录当前批次的id
            final Object g = generation;

            int index = ++ count;
            //批次已经达到parties
            if(index == parties) {
                //进入下一批次
                nextGeneration();
                return;
            }
            //若未达到批次,就进入等待
            for (;;) {
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (g != generation) {
                    return;
                }
            }

        } finally {
            lock.unlock();
        }
    }
    
}

开启线程

开启一个新的线程本质上去讲只有一种方法->new Thread(){}.start();,虽然我们平时可以使用多种方式去实现如:Runnable、Callable

import java.util.concurrent.locks.LockSupport;

public class Demo2_RunnableTest {
    public static void main(String[] args) {
        Runnable cmd = new Task();
        cmd.run();
        System.out.println("5s 输出消息");
        Thread th = new Thread(cmd);
        th.start();
        System.out.println("开启线程,实现异步,立即打印消息....");
    }
}

class Task implements  Runnable {
    @Override
    public void run() {
        System.out.println("run 方法开始执行");
        LockSupport.parkNanos(1000*1000*1000*5l);
    }
}

Callable相比于Runnable,可以获取结果

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.locks.LockSupport;

public class Demo3_CallableTest {
    public static void main(String[] args) throws  InterruptedException, ExecutionException {
        CallTask cTask =new CallTask();
        //futureTask只能执行一次
        FutureTask fTask = new FutureTask(cTask);

        Thread th = new Thread(fTask);
        th.start();
        System.out.println((String)fTask.get());
    }
}

class CallTask implements Callable<String> {
    @Override
    public String call() throws Exception {
        LockSupport.parkNanos(1000*1000*1000*5L);
        System.out.println("done....");
        return "11";
    }
}

FutureTask

import java.util.concurrent.Callable;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;

public class TomFutureTask<T> implements Runnable {

    //future只能执行一次,简单的分为3种状态,实际更多
    private volatile int state = NEW;
    private static final int NEW = 0;
    private static final int RUNNING = 1;
    private static final int FINISED = 2;

    //返回的结果
    private T result;

    //要自行的task
    Callable<T> callable;

    public TomFutureTask(Callable<T> task) {
        this.callable = task;
    }

    //获取结果的线程等待队列
    LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>(100);

    //执行当前futureTask的线程,用cas进行争抢
    AtomicReference<Thread> runner = new AtomicReference<>();

    @Override
    public void run() {
        if (state  != NEW || runner.compareAndSet(null,Thread.currentThread())) {
            return;
        }
        state=RUNNING;

        try {
            result = callable.call();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            state = FINISED;
        }

        //方法执行完,唤醒所有线程
        while (true) {
            Thread waiter = waiters.poll();
            if (waiter == null) {
                break;
            }
            LockSupport.unpark(waiter);
        }
    }

    public T get() {
        if (state != FINISED) {
            waiters.offer(Thread.currentThread());
        }
        while (state != FINISED) {
            LockSupport.park();
        }
        return result;
    }
}

ForkJoin并发处理框架

ForkJoinPool是ExecutorService接口的实现,它专为可以递归分解成小块的工作而设计。
fork/join框架将任务分配给线程池中的工作线程,充分利用多处理器的优势,提高程序性能。
使用fork/join框架的第一步是编写执行一部分工作的代码。类似的伪代码如下:
如果(当前工作部分足够小)
直接做这个工作
其他
把当前工作分成两部分
调用这两个部分并等待结果
将此代码包装在ForkJoinTask子类中,通常是RecursiveTask(可以返回结果)或者RecursiveAction。
分解任务fork出新任务,汇集join任务执行结果。
在这里插入图片描述
使用实例:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveTask;

public class ForkJoinTest {

    static ArrayList<String> urls = new ArrayList<String>(){
        {
            add("http://www.baidu.com");
            add("http://www.sina.com");
            add("http://www.baidu.com");
			···
            add("http://www.baidu.com");
            add("http://www.sina.com");
            add("http://www.baidu.com");
            add("http://www.sina.com");
            add("http://www.baidu.com");
            add("http://www.sina.com");
            add("http://www.baidu.com");
            add("http://www.sina.com");
            add("http://www.baidu.com");
            add("http://www.sina.com");
            add("http://www.baidu.com");
            add("http://www.sina.com");
            add("http://www.baidu.com");
            add("http://www.sina.com");
            add("http://www.baidu.com");
            add("http://www.sina.com");
        }
    };
		static ForkJoinPool firkJoinPool = new ForkJoinPool(3,
           		 ForkJoinPool.defaultForkJoinWorkerThreadFactory,
          		  null,
        		    true);
  
    public static void main(String[] args) {
		Job job = new Job(urls, 0, urls.size());
        ForkJoinTask<String> forkJoinTask = firkJoinPool.submit(job);

        String result = forkJoinTask.get();
        System.out.println(result);
    }

    public static  String doRequest(String url) {
        return "Kody ... test ... " + url + "\n";
    }

    static class Job extends RecursiveTask<String> {
        List<String> urls;

        int start;
        int end;

        public Job(List<String> urls, int start, int end) {
            this.urls = urls;
            this.start = start;
            this.end = end;
        }

        @Override
        protected String compute() {
            //计算任务的大小
            int count = end - start;

            if (count <= 10) {
                //直接执行
                String result = "";
                for (int i = start; i<end; i++) {
                    String response = doRequest(urls.get(i));
                    result += response;
                }
                return result;
            } else {
                //继续拆分任务
                int x = (start + end) / 2;

                Job job1 = new Job(urls, start,x);
                job1.fork();

                Job job2 = new Job(urls, x, end);
                job2.fork();

                //固定写法
                String result = "";
                result += job1.join();
                result += job2.join();
                return result;
            }
        }
    }
}

适用:使用尽可能少的线程池-在大多数情况下,最好的决定是为每一个应用程序或系统使用一个线程池,如果不需要特定的调整,请使用默认的公共线程池。使用合理的阈值将ForkJoinTask拆分为子任务,避免在ForkJoinTask中出现任何阻塞
适合数据处理、结果汇总、统计等场景;
java8实例:java.util.Arrays类用于其parallelSort()方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值