java并发常用类

来源:互联网 发布:pop3默认端口号 编辑:程序博客网 时间:2024/06/14 16:57

    • 阻塞队列BlockingQueue
    • CallableFuture和FutureTask
      • 使用CallableFuture获得执行的结果
      • 使用CallableFutureTask获得执行的结果
    • CountDownLatch用法
    • CyclicBarrier用法
    • Semaphore用法

阻塞队列BlockingQueue

从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种:

  • 当队列满了的时候禁止入队列操作
  • 当队列空了的时候禁止出队列操作
    用法:阻塞队列主要用在生产者/消费者的场景,下面这幅图展示了一个线程生产、一个线程消费的场景
    这里写图片描述
package com.koma.demo;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;/** * @author koma * @version 2017年12月1日 上午10:32:19 */public class BlockingQueueTest {    public static void main(String[] args) {        BlockingQueue<String> queue=new ArrayBlockingQueue<>(2);        Consumer consumer=new Consumer(queue);        Producer producer=new Producer(queue);        consumer.start();        producer.start();    }    static class  Consumer extends Thread{        BlockingQueue<String> queue;        public Consumer(BlockingQueue<String> queue){            this.queue=queue;        }        @Override        public void run() {            while(true){                try {                    String s=queue.take();                    System.out.println("消费者消费: "+s);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    static class Producer extends Thread{        BlockingQueue<String> queue;        public Producer(BlockingQueue<String> queue){            this.queue=queue;        }        @Override        public void run() {            while(true){                try {                    for(int i=0;i<5;i++){                        queue.put(System.currentTimeMillis()+" "+i);                        System.out.println("生产者生产!"+i);                    }                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}

Callable,Future和FutureTask

Callable:有返回值的Runnable。
Future:接口是用来获取异步计算结果的,说白了就是对具体的Runnable或者Callable对象任务执行的结果进行获取(get()),取消(cancel()),判断是否完成等操作。
FutureTask:除了实现了Future接口外还实现了Runnable接口,因此FutureTask也可以直接提交给Executor执行
具体有哪些方法请查看api文档。

使用Callable+Future获得执行的结果

package com.koma.demo;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * @author koma * @version 2017年12月1日 上午11:06:11 */public class FutureTest {    public static void main(String[] args) {        ExecutorService service=Executors.newSingleThreadExecutor();        Future<Integer> future=service.submit(new CallableDome());        try {            int i=future.get();//会阻塞等待结果返回            System.out.println("callble 返回的结果是: "+i);            service.shutdown();        } catch (InterruptedException | ExecutionException e) {            e.printStackTrace();        }    }    static class CallableDome implements Callable<Integer>{        @Override        public Integer call() throws Exception {            return 1;        }    }}

使用Callable+FutureTask获得执行的结果

package com.koma.demo;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.FutureTask;/** * @author koma * @version 2017年12月1日 上午10:57:24 */public class FutureTaskTest {    public static void main(String[] args) {        ExecutorService service=Executors.newSingleThreadExecutor();        FutureTask<Integer> task=new FutureTask<>(new CallableDome());        service.submit(task);        try {            int i=task.get(); //会阻塞等待结果返回            System.out.println("callble 返回的结果是: "+i);            service.shutdown();        } catch (InterruptedException | ExecutionException e) {            e.printStackTrace();        }    }    static class CallableDome implements Callable<Integer>{        @Override        public Integer call() throws Exception {            return 1;        }    }}

CountDownLatch用法

情景:比如有一个任务A,它要等待其他几个线程执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

package com.koma.demo;import java.util.concurrent.CountDownLatch;/** * @author koma * @version 2017年12月1日 下午1:57:58 */public class CountDownLatchTest {    public static void main(String[] args) {        CountDownLatch latch = new CountDownLatch(2);//初始化count值        new Thread(new Runnable() {            @Override            public void run() {                System.out.println("子线程" + Thread.currentThread().getName() + "开始运行");                try {                    Thread.sleep(3000);// 模拟任务运行                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("子线程" + Thread.currentThread().getName() + "结束运行");                latch.countDown();//将count值减1            }        }).start();        new Thread(new Runnable() {            @Override            public void run() {                System.out.println("子线程" + Thread.currentThread().getName() + "开始运行");                try {                    Thread.sleep(3000);// 模拟任务运行                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("子线程" + Thread.currentThread().getName() + "结束运行");                latch.countDown();  //将count值减1            }        }).start();        System.out.println("主线程执行任务,但是得等待所有的子线程执行完,才能运行!");        try {            latch.await();  //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("2个子线程已经执行完毕");        System.out.println("继续执行主线程");    }}

CyclicBarrier用法

字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。

package com.koma.demo;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;/** * @author koma * @version 2017年12月1日 下午2:27:52 */public class CyclicBarrierTest {    public static void main(String[] args) {        int n=3;        CyclicBarrier barrier=new CyclicBarrier(n);        for(int i=0;i<n;i++){            Demo demo=new Demo(barrier);            demo.start();        }    }    static class Demo extends Thread{        private CyclicBarrier cyclicBarrier;        public Demo(CyclicBarrier cyclicBarrier){            this.cyclicBarrier=cyclicBarrier;        }        @Override        public void run() {            System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");            try {                Thread.sleep(2000);//以睡眠来模拟写入数据操作                System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");                cyclicBarrier.await();  //线程在这等待了,所有线程都运行到这了,才会继续往下运行            } catch (InterruptedException | BrokenBarrierException e) {                e.printStackTrace();            }            System.out.println("所有线程写入完毕,继续处理其他任务...");        }    }}

CyclicBarrier构造还可以指定一个Runable参数

package com.koma.demo;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;/** * @author koma * @version 2017年12月1日 下午2:27:52 */public class CyclicBarrierTest {    public static void main(String[] args) {        int n=3;        CyclicBarrier barrier=new CyclicBarrier(n,new Runnable() {            @Override            public void run() {                // 选择其中一个线程运行                System.out.println("线程名字: "+Thread.currentThread().getName());            }        });        for(int i=0;i<n;i++){            Demo demo=new Demo(barrier);            demo.start();        }    }    static class Demo extends Thread{        private CyclicBarrier cyclicBarrier;        public Demo(CyclicBarrier cyclicBarrier){            this.cyclicBarrier=cyclicBarrier;        }        @Override        public void run() {            System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");            try {                Thread.sleep(2000);//以睡眠来模拟写入数据操作                System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");                cyclicBarrier.await();  //线程在这等待了,所有线程都运行到这了,才会继续往下运行            } catch (InterruptedException | BrokenBarrierException e) {                e.printStackTrace();            }            System.out.println("所有线程写入完毕,继续处理其他任务...");        }    }}

CyclicBarrier可以重用

package com.koma.demo;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;/** * @author koma * @version 2017年12月1日 下午2:27:52 */public class CyclicBarrierTest {    public static void main(String[] args) {        int n=3;        CyclicBarrier barrier=new CyclicBarrier(n);        for(int i=0;i<n;i++){            Demo demo=new Demo(barrier);            demo.start();        }        try {            Thread.sleep(5000);        } catch (InterruptedException e) {            e.printStackTrace();        }        for(int i=0;i<n;i++){            Demo demo=new Demo(barrier);            demo.start();        }    }    static class Demo extends Thread{        private CyclicBarrier cyclicBarrier;        public Demo(CyclicBarrier cyclicBarrier){            this.cyclicBarrier=cyclicBarrier;        }        @Override        public void run() {            System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");            try {                Thread.sleep(1000);//以睡眠来模拟写入数据操作                System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");                cyclicBarrier.await();  //线程在这等待了,所有线程都运行到这了,才会继续往下运行            } catch (InterruptedException | BrokenBarrierException e) {                e.printStackTrace();            }            System.out.println("所有线程写入完毕,继续处理其他任务...");        }    }}

Semaphore用法

Semaphore翻译成字面意思为 信号量,Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
用Semaphore来控制set的容量大小

package com.koma.demo;import java.util.HashSet;import java.util.Set;import java.util.concurrent.Semaphore;/** * @author koma * @version 2017年12月1日 下午3:43:06 */public class SemaphoreTest {    private Set<Integer> set;    private Semaphore semaphore;    public SemaphoreTest(int n) {        this.set = new HashSet<>();        this.semaphore = new Semaphore(n);    }    public boolean add(Integer s) {        // 获得一个许可        try {            semaphore.acquire();        } catch (InterruptedException e) {            e.printStackTrace();        }        boolean was = false;        try {            was = set.add(s);            return was;        } finally {            // 如果添加失败,一定要释放许可            if (!was) {                semaphore.release();            }        }    }    public boolean remove(Integer s) {        boolean was = set.remove(s);        if (was) { // 如果移除成功了,释放许可            semaphore.release();        }        return was;    }    public static void main(String[] args) {        // set容纳的元素不可能大于3        SemaphoreTest test=new SemaphoreTest(3);        new Thread(){            @Override            public void run() {                while(true){                    for(int i=0;i<5;i++){                        test.add(i); // 添加元素                        System.out.println(Thread.currentThread().getName()+" set size: "+test.set.size());                        try {                            Thread.sleep(1000);                        } catch (InterruptedException e) {                            // TODO Auto-generated catch block                            e.printStackTrace();                        }                    }                }            }        }.start();        new Thread(){            @Override            public void run() {                while(true){                    for(int i=0;i<5;i++){                        test.remove(i); // 移除元素                        System.out.println(Thread.currentThread().getName()+" set size: "+test.set.size());                        try {                            Thread.sleep(2000);                        } catch (InterruptedException e) {                            // TODO Auto-generated catch block                            e.printStackTrace();                        }                    }                }            }        }.start();    }}