Java并发编程之并发包

java并发包介绍

JDK5.0 以后的版本都引入了高级并发特性,大多数的特性在java.util.concurrent 包中,是专门用于多线程发编程的,充分利用了现代多处理器和多核心系统的功能以编写大规模并发应用程序。主要包含原子量、并发集合、同步器、可重入锁,并对线程池的构造提供了强力的支持。

线程池

线程池的5中创建方式

1、 Single Thread Executor : 只有一个线程的线程池,因此所有提交的任务是顺序执行,
代码: Executors.newSingleThreadExecutor()

2、 Cached Thread Pool : 线程池里有很多线程需要同时执行,老的可用线程将被新的任务触发重新执行,如果线程超过60秒内没执行,那么将被终止并从池中删除,
代码:Executors.newCachedThreadPool()

3、 Fixed Thread Pool : 拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待,
代码: Executors.newFixedThreadPool(4)
在构造函数中的参数4是线程池的大小,你可以随意设置,也可以和cpu的核数量保持一致,获取cpu的核数量int cpuNums = Runtime.getRuntime().availableProcessors();

4、 Scheduled Thread Pool : 用来调度即将执行的任务的线程池,可能是不是直接执行, 每隔多久执行一次… 策略型的
代码:Executors.newScheduledThreadPool()

5、 Single Thread Scheduled Pool : 只有一个线程,用来调度任务在指定时间执行,代码:Executors.newSingleThreadScheduledExecutor()

package cn.itcast_01_mythread.pool;

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

/**
 * 列出并发包中的各种线程池
 * @author
 *
 */

public class ExecutorDemo {

    public static void main(String[] args) {
        ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

        int cpuNums = Runtime.getRuntime().availableProcessors();
        System.out.println(cpuNums);
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(cpuNums);
        ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(8);


        ScheduledExecutorService newSingleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
    }
}

线程池的使用

提交 Runnable ,任务完成后 Future 对象返回 null
调用excute,提交任务, 匿名Runable重写run方法, run方法里是业务逻辑
见代码:ThreadPoolWithRunable

package cn.itcast_01_mythread.pool;

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

public class ThreadPoolWithRunable {


    /**
     * 通过线程池执行线程
     * @param args
     */
    public static void main(String[] args) {
        //创建一个线程池
        ExecutorService pool = Executors.newCachedThreadPool();
        for(int i = 1; i < 5; i++){
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("thread name: " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        pool.shutdown();
    }

}

这里写图片描述


package cn.itcast_01_mythread.pool;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.sun.corba.se.impl.encoding.OSFCodeSetRegistry.Entry;

public class TestPool {

    public static void main(String[] args) throws Exception {
        Future<?> submit = null;
        Random random = new Random();

        //创建固定数量线程池
//      ExecutorService exec = Executors.newFixedThreadPool(4);

        //创建调度线程池
        ScheduledExecutorService exec = Executors.newScheduledThreadPool(4);

        //用来记录各线程的返回结果
        ArrayList<Future<?>> results = new ArrayList<Future<?>>();

        for (int i = 0; i < 10; i++) {
            //fixedPool提交线程,runnable无返回值,callable有返回值
            submit = exec.submit(new TaskRunnable(i));
            /*submit = exec.submit(new TaskCallable(i));*/

            //对于schedulerPool来说,调用submit提交任务时,跟普通pool效果一致
            /*submit = exec.submit(new TaskCallable(i));*/
            //对于schedulerPool来说,调用schedule提交任务时,则可按延迟,按间隔时长来调度线程的运行
            //submit = exec.schedule(new TaskCallable(i), random.nextInt(10), TimeUnit.SECONDS);
            //存储线程执行结果
            results.add(submit);

        }


        //打印结果
        for(Future f: results){
            boolean done = f.isDone();
            System.out.println(done?"已完成":"未完成");  //从结果的打印顺序可以看到,即使未完成,也会阻塞等待
            System.out.println("线程返回future结果: " + f.get());
        }

        exec.shutdown();

    }
}
package cn.itcast_01_mythread.pool;

import java.util.Random;

public class TaskRunnable implements Runnable{
    private int s;

    public TaskRunnable(int s){
        this.s = s;
    }

    Random r = new Random();

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        long currentTimeMillis = System.currentTimeMillis();
        System.out.println(name+" 启动时间:" + currentTimeMillis/1000);

        int rint = r.nextInt(3);
        try {
            Thread.sleep(rint*1000);
        } catch (InterruptedException e) {

            e.printStackTrace();
        }
        System.out.println(name + " is working..."+s);

    }

}

这里写图片描述

提交 Callable,该方法返回一个 Future 实例表示任务的状态
调用submit提交任务, 匿名Callable,重写call方法, 有返回值, 获取返回值会阻塞,一直要等到线程任务返回结果
见代码:ThreadPoolWithcallable

package cn.itcast_01_mythread.pool;

import java.util.ArrayList;
import java.util.List;
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;
/**
 * callable 跟runnable的区别:
 * runnable的run方法不会有任何返回结果,所以主线程无法获得任务线程的返回值
 * 
 * callable的call方法可以返回结果,但是主线程在获取时是被阻塞,需要等待任务线程返回才能拿到结果
 * @author
 *
 */
public class ThreadPoolWithcallable {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService pool = Executors.newFixedThreadPool(4); 

        for(int i = 0; i < 10; i++){
            Future<String> submit = pool.submit(new Callable<String>(){
                @Override
                public String call() throws Exception {
                    //System.out.println("a");
                    Thread.sleep(5000);
                    return "b--"+Thread.currentThread().getName();
                }              
               });
            //从Future中get结果,这个方法是会被阻塞的,一直要等到线程任务返回结果
            System.out.println(submit.get());
        } 
            pool.shutdown();

    }

}

这里写图片描述


package cn.itcast_01_mythread.pool;

import java.util.Random;
import java.util.concurrent.Callable;

public class TaskCallable implements Callable<String>{

    private int s;
    Random r = new Random();
    public TaskCallable(int s){
        this.s = s;
    }

    @Override
    public String call() throws Exception {
        String name = Thread.currentThread().getName();
        long currentTimeMillis = System.currentTimeMillis();
        System.out.println(name+" 启动时间:" + currentTimeMillis/1000);

        int rint = r.nextInt(3);
        try {
            Thread.sleep(rint*1000);
        } catch (InterruptedException e) {

            e.printStackTrace();
        }
        System.out.println(name + " is working..."+s);
        return s+"";
    }

}
package cn.itcast_01_mythread.pool;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.sun.corba.se.impl.encoding.OSFCodeSetRegistry.Entry;

public class TestPool {

    public static void main(String[] args) throws Exception {
        Future<?> submit = null;
        Random random = new Random();

        //创建固定数量线程池
//      ExecutorService exec = Executors.newFixedThreadPool(4);

        //创建调度线程池
        ScheduledExecutorService exec = Executors.newScheduledThreadPool(4);

        //用来记录各线程的返回结果
        ArrayList<Future<?>> results = new ArrayList<Future<?>>();

        for (int i = 0; i < 10; i++) {
            //fixedPool提交线程,runnable无返回值,callable有返回值
            /*submit = exec.submit(new TaskRunnable(i));*/
            /*submit = exec.submit(new TaskCallable(i));*/

            //对于schedulerPool来说,调用submit提交任务时,跟普通pool效果一致
            //submit = exec.submit(new TaskCallable(i));
            //对于schedulerPool来说,调用schedule提交任务时,则可按延迟,按间隔时长来调度线程的运行
            submit = exec.schedule(new TaskCallable(i), random.nextInt(10), TimeUnit.SECONDS);
            //存储线程执行结果
            results.add(submit);

        }


        //打印结果
        for(Future f: results){
            boolean done = f.isDone();
            System.out.println(done?"已完成":"未完成");  //从结果的打印顺序可以看到,即使未完成,也会阻塞等待
            System.out.println("线程返回future结果: " + f.get());
        }

        exec.shutdown();

    }
}

这里写图片描述

java并发包消息队列及在开源软件中的应用

BlockingQueue

BlockingQueue也是java.util.concurrent下的主要用来控制线程同步的工具。
主要的方法是:put、take一对阻塞存取;add、poll一对非阻塞存取。

插入:

1)add(anObject)
把anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则抛出异常,不好
2)offer(anObject)
表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false.
3)put(anObject)
把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续, 有阻塞, 放不进去就等待

读取:

1)poll(time)
取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null; 取不到返回null
2)take()
取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止; 阻塞, 取不到就一直等

其他

int remainingCapacity();返回队列剩余的容量,在队列插入和获取的时候,不要瞎搞,数 据可能不准, 不能保证数据的准确性
boolean remove(Object o); 从队列移除元素,如果存在,即移除一个或者更多,队列改 变了返回true
public boolean contains(Object o); 查看队列是否存在这个元素,存在返回true
int drainTo(Collection<? super E> c); //移除此队列中所有可用的元素,并将它们添加到给定 collection 中。取出放到集合中
int drainTo(Collection<? super E> c, int maxElements); 和上面方法的区别在于,指定了移 动的数量; 取出指定个数放到集合

BlockingQueue常用的两种实现类

BlockingQueue有四个具体的实现类,常用的两种实现类为:
1、ArrayBlockingQueue:一个由数组支持的有界阻塞队列,规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小.其所含的对象是以FIFO(先入先出)顺序排序的。

package cn.itcast_02_blockingqueue.main;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import cn.itcast_02_blockingqueue.consumer.Consumer;
import cn.itcast_02_blockingqueue.producer.Producer;

public class Test {
    public static void main(String[] args) throws Exception {
        BlockingQueue<String> queue = new ArrayBlockingQueue<String>(2);
        Consumer consumer = new Consumer(queue);
        Producer producer = new Producer(queue);
        for (int i = 0; i < 3; i++) {
            new Thread(producer, "Producer" + (i + 1)).start();
        }
        for (int i = 0; i < 5; i++) {
            new Thread(consumer, "Consumer" + (i + 1)).start();
        }

        new Thread(producer, "Producer" + (5)).start();
    }
}
package cn.itcast_02_blockingqueue.producer;

import java.util.concurrent.BlockingQueue;

public class Producer implements Runnable {  
    BlockingQueue<String> queue;    
    public Producer(BlockingQueue<String> queue) {  
        this.queue = queue;  
    }    
    @Override  
    public void run() {  
        try {  

            System.out.println("I have made a product:"  
                    + Thread.currentThread().getName()); 
            String temp = "A Product, 生产线程:"  
                    + Thread.currentThread().getName();  
            queue.put(temp);//如果队列是满的话,会阻塞当前线程  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }    
}  

package cn.itcast_02_blockingqueue.consumer;

import java.util.concurrent.BlockingQueue;

public class Consumer implements Runnable{  
    BlockingQueue<String> queue; 
    public Consumer(BlockingQueue<String> queue){  
        this.queue = queue;  
    }        
    @Override  
    public void run() {  
        try {  
            String consumer = Thread.currentThread().getName();
            System.out.println(consumer);  
            String temp = queue.take();//如果队列为空,会阻塞当前线程  
            System.out.println(consumer+"get a product:"+temp);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
}  

这里写图片描述

2、LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定.其所含的对象是以FIFO(先入先出)顺序排序的。
LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到puttake方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。

package cn.itcast_02_blockingqueue.main;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import cn.itcast_02_blockingqueue.consumer.Consumer;
import cn.itcast_02_blockingqueue.producer.Producer;

public class Test {
    public static void main(String[] args) throws Exception {
        BlockingQueue<String> queue = new LinkedBlockingQueue<String>(2);
        // BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
        // 不设置的话,LinkedBlockingQueue默认大小为Integer.MAX_VALUE
        // BlockingQueue<String> queue = new ArrayBlockingQueue<String>(2);
        Consumer consumer = new Consumer(queue);
        Producer producer = new Producer(queue);
        for (int i = 0; i < 3; i++) {
            new Thread(producer, "Producer" + (i + 1)).start();
        }
        for (int i = 0; i < 5; i++) {
            new Thread(consumer, "Consumer" + (i + 1)).start();
        }

        new Thread(producer, "Producer" + (5)).start();
    }
}

这里写图片描述
LinkedBlockingQueue和ArrayBlockingQueue区别
LinkedBlockingQueue和ArrayBlockingQueue比较起来,它们背后所用的数据结构不一样,导致LinkedBlockingQueue的数据吞吐量要大于ArrayBlockingQueue,但在线程数量很大时其性能的可预见性低于ArrayBlockingQueue.

生产者消费者的示例代码:

package cn.itcast_02_blockingqueue.main;

import java.util.Random;
import java.util.concurrent.BlockingQueue;

public class TestBlockingQueueConsumer implements Runnable{  
    BlockingQueue<String> queue; 
    Random random = new Random();

    public TestBlockingQueueConsumer(BlockingQueue<String> queue){  
        this.queue = queue;  
    }        
    @Override  
    public void run() {  
        try {  
            Thread.sleep(random.nextInt(10));
            System.out.println(Thread.currentThread().getName()+ "trying...");
            String temp = queue.take();//如果队列为空,会阻塞当前线程  
            System.out.println(Thread.currentThread().getName() + " get a job " +temp);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
}
package cn.itcast_02_blockingqueue.main;

import java.util.Random;
import java.util.concurrent.BlockingQueue;

public class TestBlockingQueueProducer implements Runnable {
    BlockingQueue<String> queue;
    Random random = new Random();

    public TestBlockingQueueProducer(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {

        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(random.nextInt(10));
                String task = Thread.currentThread().getName() + " made a product " + i;

                System.out.println(task);
                queue.put(task);
            } catch (InterruptedException e) {

                e.printStackTrace();
            }

        }

    }

}
package cn.itcast_02_blockingqueue.main;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class TestBlockingQueue {

    public static void main(String[] args) {


        //BlockingQueue<String> queue = new LinkedBlockingQueue<String>(2);
        // BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
        // 不设置的话,LinkedBlockingQueue默认大小为Integer.MAX_VALUE
        BlockingQueue<String> queue = new ArrayBlockingQueue<String>(2);
        TestBlockingQueueConsumer consumer = new TestBlockingQueueConsumer(queue);
        TestBlockingQueueProducer producer = new TestBlockingQueueProducer(queue);
        for (int i = 0; i < 3; i++) {
            new Thread(producer, "Producer" + (i + 1)).start();
        }
        for (int i = 0; i < 5; i++) {
            new Thread(consumer, "Consumer" + (i + 1)).start();
        }

        new Thread(producer, "Producer" + (5)).start();




    }


}

这里写图片描述

package cn.itcast_02_blockingqueue.main;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class TestBlockingQueue {

    public static void main(String[] args) {


        BlockingQueue<String> queue = new LinkedBlockingQueue<String>(2);
        // BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
        // 不设置的话,LinkedBlockingQueue默认大小为Integer.MAX_VALUE
        // BlockingQueue<String> queue = new ArrayBlockingQueue<String>(2);
        TestBlockingQueueConsumer consumer = new TestBlockingQueueConsumer(queue);
        TestBlockingQueueProducer producer = new TestBlockingQueueProducer(queue);
        for (int i = 0; i < 3; i++) {
            new Thread(producer, "Producer" + (i + 1)).start();
        }
        for (int i = 0; i < 5; i++) {
            new Thread(consumer, "Consumer" + (i + 1)).start();
        }

        new Thread(producer, "Producer" + (5)).start();




    }


}

这里写图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值