java 高级并发_Java高级特性—并发包

1). java并发包介绍

JDK5.0 以后的版本都引入了高级并发特性,大多数的特性在java.util.concurrent 包中,是专门用于多线程发编程的,

主要包含原子量、并发集合、同步器、可重入锁,并对线程池的构造提供了强力的支持。

2).线程池的创建

线程池的5中创建方式:

a、Single Thread Executor : 只有一个线程的线程池,因此所有提交的任务是顺序执行,

代码: Executors.newSingleThreadExecutor()

b、Cached Thread Pool : 线程池里有很多线程需要同时执行,老的可用线程将被新的任务触发重新执行,

如果线程超过60秒内没执行,那么将被终止并从池中删除,

代码:Executors.newCachedThreadPool()

c、Fixed Thread Pool : 拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待,

代码: Executors.newFixedThreadPool(4)

在构造函数中的参数4是线程池的大小,你可以随意设置,也可以和cpu的核数量保持一致,获取cpu的核数量int

cpuNums = Runtime.getRuntime().availableProcessors();

d、Scheduled Thread Pool : 用来调度即将执行的任务的线程池,

代码:Executors.newScheduledThreadPool()

e、Single Thread Scheduled Pool : 只有一个线程,用来调度任务在指定时间执行,

代码:Executors.newSingleThreadScheduledExecutor()

3).线程池的使用

提交 Runnable ,任务完成后 Future 对象返回 null

提交 Callable,该方法返回一个 Future 实例表示任务的状态

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

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里面有空间再继续读取:

4) poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null

5) 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有四个具体的实现类,常用的两种实现类为:

a、ArrayBlockingQueue:一个由数组支持的有界阻塞队列,规定大小的BlockingQueue,

其构造函数必须带一个int参数来指明其大小.其所含的对象是以FIFO(先入先出)顺序排序的。

b、LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue

有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定.其所含的对象是

以FIFO(先入先出)顺序排序的。

LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用

到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,

直到有队列成员被放进来。

c、LinkedBlockingQueue和ArrayBlockingQueue区别:

LinkedBlockingQueue和ArrayBlockingQueue比较起来,它们背后所用的数据结构不一样,

导致LinkedBlockingQueue的数据吞吐量要大于ArrayBlockingQueue,但在线程数量很大时其性能的

可预见性低于ArrayBlockingQueue.

4).不应用线程池的缺点

有些开发者图省事,遇到需要多线程处理的地方,直接new Thread(...).start(),对于一般场景是没问题的,

但如果是在并发请求很高的情况下,就会有些隐患:

a).新建线程的开销。线程虽然比进程要轻量许多,但对于JVM来说,新建一个线程的代价还是挺大的,决不同于新建一个对象

b).资源消耗量。没有一个池来限制线程的数量,会导致线程的数量直接取决于应用的并发量,这样有潜在的线程数据

巨大的可能,那么资源消耗量将是巨大的

c).稳定性。当线程数量超过系统资源所能承受的程度,稳定性就会成问题

5).制定执行策略

在每个需要多线程处理的地方,不管并发量有多大,需要考虑线程的执行策略

a.任务以什么顺序执行

b.可以有多少个任务并发执行

c.可以有多少个任务进入等待执行队列

d.系统过载的时候,应该放弃哪些任务?如何通知到应用程序?

e.一个任务的执行前后应该做什么处理

6).线程池的类型

不管是通过Executors创建线程池,还是通过Spring来管理,都得清楚知道有哪几种线程池:

a.FixedThreadPool:定长线程池,提交任务时创建线程,直到池的最大容量,如果有线程非预期结束,会补充新线程

b.CachedThreadPool:可变线程池,它犹如一个弹簧,如果没有任务需求时,它回收空闲线程,如果需求增加,则按需增加线程,不对池的大小做限制

c.SingleThreadExecutor:单线程。处理不过来的任务会进入FIFO队列等待执行

d.SecheduledThreadPool:周期性线程池。支持执行周期性线程任务

其实,这些不同类型的线程池都是通过构建一个ThreadPoolExecutor来完成的,所不同的是corePoolSize,

maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory这么几个参数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值