java线程池队列代码,Java线程池代码

java线程池(一) 简述线程池的几种使用方式

首先说明下java线程是如何实现线程重用的

公司主营业务:网站制作、成都网站设计、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联推出仪征免费做网站回馈大家。

1. 线程执行完一个Runnable的run()方法后,不会被杀死

2. 当线程被重用时,这个线程会进入新Runnable对象的run()方法12

java线程池由Executors提供的几种静态方法创建线程池。下面通过代码片段简单介绍下线程池的几种实现方式。后续会针对每个实现方式做详细的说明

newFixedThreadPool

创建一个固定大小的线程池

添加的任务达到线程池的容量之后开始加入任务队列开始线程重用总共开启线程个数跟指定容量相同。

@Test

public void newFixedThreadPool() throws Exception {

ExecutorService executorService = Executors.newFixedThreadPool(1);

executorService = Executors.newFixedThreadPool(1, new ThreadFactoryBuilder().build());

RunThread run1 = new RunThread("run 1");

executorService.execute(run1);

executorService.shutdown();

}12345678

newSingleThreadExecutor

仅支持单线程顺序处理任务

@Test

public void newSingleThreadExecutor() throws Exception {

ExecutorService executorService = Executors.newSingleThreadExecutor();

executorService = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().build());

executorService.execute(new RunThread("run 1"));

executorService.execute(new RunThread("run 2"));

executorService.shutdown();

}123456789

newCachedThreadPool

这种情况跟第一种的方式类似,不同的是这种情况线程池容量上线是Integer.MAX_VALUE 并且线程池开启缓存60s

@Test

public void newCachedThreadPool() throws Exception {

ExecutorService executorService = Executors.newCachedThreadPool();

executorService = Executors.newCachedThreadPool(new ThreadFactoryBuilder().build());

executorService.execute(new RunThread("run 1"));

executorService.execute(new RunThread("run 2"));

executorService.shutdown();

}123456789

newWorkStealingPool

支持给定的并行级别,并且可以使用多个队列来减少争用。

@Test

public void newWorkStealingPool() throws Exception {

ExecutorService executorService = Executors.newWorkStealingPool();

executorService = Executors.newWorkStealingPool(1);

RunThread run1 = new RunThread("run 1");

executorService.execute(run1);

executorService.shutdown();

}123456789

newScheduledThreadPool

看到的现象和第一种相同,也是在线程池满之前是新建线程,然后开始进入任务队列,进行线程重用

支持定时周期执行任务(还没有看完)

@Test

public void newScheduledThreadPool() throws Exception {

ExecutorService executorService = Executors.newScheduledThreadPool(1);

executorService = Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().build());

executorService.execute(new RunThread("run 1"));

executorService.execute(new RunThread("run 2"));

executorService.shutdown();

}

线程池-参数篇:2.队列

多线程环境中,通过队列可以很容易实现线程间数据共享,比如经典的“生产者”和“消费者”模型中,通过队列可以很便利地实现两者之间的数据共享;同时作为BlockingQueue的使用者,我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切BlockingQueue的实现者都给一手包办了。

基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,另外还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。

ArrayBlockingQueue在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行,而在创建ArrayBlockingQueue时,我们还可以控制对象的内部锁是否采用公平锁,默认采用非公平锁。

按照实现原理来分析,ArrayBlockingQueue完全可以采用分离锁,从而实现生产者和消费者操作的完全并行运行。

基于链表的阻塞队列,其内部也维持着一个数据缓冲队列(由一个链表构成),当生产者往队列中放入一个数据时,队列会从生产者手中获取数据,并缓存在队列内部,而生产者立即返回;只有当队列缓冲区达到最大值缓存容量时(LinkedBlockingQueue可以通过构造函数指定该值),才会阻塞生产者队列,直到消费者从队列中消费掉一份数据,生产者线程会被唤醒,反之对于消费者这端的处理也基于同样的原理。

对于生产者端和消费者端分别采用了独立的锁来控制数据同步,这也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。

ArrayBlockingQueue和LinkedBlockingQueue间还有一个明显的不同之处在于,前者在插入或删除元素时不会产生或销毁任何额外的对象实例,而后者则会生成一个额外的Node对象。这在长时间内需要高效并发地处理大批量数据的系统中,其对于GC的影响还是存在一定的区别。如果没有指定其容量大小,LinkedBlockingQueue会默认一个类似无限大小的容量(Integer.MAX_VALUE),这样的话,如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。

ArrayBlockingQueue和LinkedBlockingQueue是两个最普通也是最常用的阻塞队列,一般情况下,在处理多线程间的生产者消费者问题,使用这两个类足以。

DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue是一个没有大小限制的队列,因此往队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞。

DelayQueue用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。注意:不能将null元素放置到这种队列中。

Delayed 是一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象。Delayed扩展了Comparable接口,比较的基准为延时的时间值,Delayed接口的实现类getDelay的返回值应为固定值(final)。DelayQueue内部是使用PriorityQueue实现的。

考虑以下场景:

一种笨笨的办法就是,使用一个后台线程,遍历所有对象,挨个检查。这种笨笨的办法简单好用,但是对象数量过多时,可能存在性能问题,检查间隔时间不好设置,间隔时间过大,影响精确度,多小则存在效率问题。而且做不到按超时的时间顺序处理。

这场景,使用DelayQueue最适合了,详情查看 DelayedQueue学习笔记 ; 精巧好用的DelayQueue

基于优先级的阻塞队列(优先级的判断通过构造函数传入的Compator对象来决定),需要注意PriorityBlockingQueue并不会阻塞数据生产者,而只会在没有可消费的数据时,阻塞数据的消费者。

使用时,若生产者生产数据的速度快于消费者消费数据的速度,随着长时间的运行,可能会耗尽所有的可用堆内存空间。在实现PriorityBlockingQueue时,内部控制线程同步的锁采用的是公平锁。

SynchronousQueue是一个内部只能包含零个元素的队列。插入元素到队列的线程被阻塞,直到另一个线程从队列中获取元素。同样,如果线程尝试获取元素并且当前没有线程在插入元素,则该线程将被阻塞,直到有线程将元素插入队列

声明一个SynchronousQueue有公平模式和非公平模式,区别如下:

参考: Java多线程-工具篇-BlockingQueue

12. SynchronousQueue

Java中关于如何实现多线程消息队列的实例

java中的消息队列

消息队列是线程间通讯的手段:

import java.util.*

public class MsgQueue{

private Vector queue = null;

public MsgQueue(){

queue = new Vector();

}

public synchronized void send(Object o)

{

queue.addElement(o);

}

public synchronized Object recv()

{

if(queue.size()==0)

return null;

Object o = queue.firstElement();

queue.removeElementAt(0);//or queue[0] = null can also work

return o;

}

}

因为java中是locked by object的所以添加synchronized 就可以用于线程同步锁定对象

可以作为多线程处理多任务的存放task的队列。他的client包括封装好的task类以及thread类

Java的多线程-线程间的通信2009-08-25 21:58

1. 线程的几种状态

线程有四种状态,任何一个线程肯定处于这四种状态中的一种:

1) 产生(New):线程对象已经产生,但尚未被启动,所以无法执行。如通过new产生了一个线程对象后没对它调用start()函数之前。

2) 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它;也可能它已正在执行。如执行了一个线程对象的start()方法后,线程就处于可执行状态,但显而易见的是此时线程不一定正在执行中。

3) 死亡(Dead):当一个线程正常结束,它便处于死亡状态。如一个线程的run()函数执行完毕后线程就进入死亡状态。

4) 停滞(Blocked):当一个线程处于停滞状态时,系统排程器就会忽略它,不对它进行排程。当处于停滞状态的线程重新回到可执行状态时,它有可能重新执行。如通过对一个线程调用wait()函数后,线程就进入停滞状态,只有当两次对该线程调用notify或notifyAll后它才能两次回到可执行状态。

2. class Thread下的常用函数函数

2.1 suspend()、resume()

1) 通过suspend()函数,可使线程进入停滞状态。通过suspend()使线程进入停滞状态后,除非收到resume()消息,否则该线程不会变回可执行状态。

2) 当调用suspend()函数后,线程不会释放它的“锁标志”。

例11:

class TestThreadMethod extends Thread{

public static int shareVar = 0;

public TestThreadMethod(String name){

super(name);

}

public synchronized void run(){

if(shareVar==0){

for(int i=0; i5; i++){

shareVar++;

if(shareVar==5){

this.suspend(); //(1)

}}}

else{

System.out.print(Thread.currentThread().getName());

System.out.println(" shareVar = " + shareVar);

this.resume(); //(2)

}}

}

public class TestThread{

public static void main(String[] args){

TestThreadMethod t1 = new TestThreadMethod("t1");

TestThreadMethod t2 = new TestThreadMethod("t2");

t1.start(); //(5)

//t1.start(); //(3)

t2.start(); //(4)

}}

Java的线程池,如何设定保留的最小线程数和固定的队列容量

创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。

看代码:

Java代码 收藏代码

package test;

import java.util.Random;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

public class ExecutorTest {

public static void main(String args[]) {

Random random = new Random();

//产生一个 ExecutorService 对象,这个对象带有一个大小为 poolSize 的线程池,若任务数量大于 poolSize ,任务会被放在一个 queue 里顺序执行。

ExecutorService executor = Executors.newFixedThreadPool(3);

// 判断可是线程池可以结束

int waitTime = 500;

for (int i = 0; i 10; i++) {

String name = "线程 " + i;

int time = random.nextInt(1000);

waitTime += time;

Runnable runner = new ExecutorThread(name, time);

System.out.println("增加: " + name + " / " + time);

executor.execute(runner);

}

try {

Thread.sleep(waitTime);

executor.shutdown();

executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);

} catch (InterruptedException ignored) {

}

}

}

class ExecutorThread implements Runnable {

private final String name;

private final int delay;

public ExecutorThread(String name, int delay) {

this.name = name;

this.delay = delay;

}

public void run() {

System.out.println("启动: " + name);

try {

Thread.sleep(delay);

} catch (InterruptedException ignored) {

}

System.out.println("完成: " + name);

}

}


分享名称:java线程池队列代码,Java线程池代码
转载源于:http://csdahua.cn/article/hedece.html
扫二维码与项目经理沟通

我们在微信上24小时期待你的声音

解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流