模拟运行一下多线程下一个队列的元素的新增、提取(删除)。
使用队列:ArrayBlockingQueue
新增元素方法offer(ele),队列满时时,不抛异常。
提取且删除元素方法poll(),队列为空时,不抛异常。
我们简单以生产消费某个数字来展示。
一、常规的多线程创建方式
代码如下:
import com.sun.javafx.binding.StringFormatter;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
public class TestZone {
public static void main(String[] args) {
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10, true);
//创建10个消费者
for (int i=0; i<10; i++) {
Thread consuTd = new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
//取出元素,不抛异常
int headNum = queue.poll(100, TimeUnit.MILLISECONDS);
System.out.println(StringFormatter.format("消费者:%s,消费掉产品%s。", Thread.currentThread().getName() , headNum).getValue());
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
}
});
consuTd.start();
}
//创建10个生产者
for (int i=0; i<10; i++) {
Thread prdTd = new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
int randomNum = new Random().nextInt()*1000 + 1;
//插入元素,队列满,不抛异常
boolean insertFlg = queue.offer(randomNum);
if(insertFlg){
System.out.println(StringFormatter.format("生产者:%s,新增产品%s。", Thread.currentThread().getName() , randomNum).getValue());
}else{
System.out.println(StringFormatter.format("生产者:%s,新增产品失败!", Thread.currentThread().getName()).getValue());
}
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
}
});
prdTd.start();
}
}
}
运行结果:
二、线程池的多线程创建方式实现
自定义一个ThreadFactory类
package demo.springboot.web;
import java.util.concurrent.ThreadFactory;
public class MyThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
System.out.println("线程:"+ t.getName() +"创建!");
return t;
}
}
线程池实现两个生产者+两个消费者:
package demo.springboot.web;
import com.sun.javafx.binding.StringFormatter;
import java.util.Random;
import java.util.concurrent.*;
public class ThreadPoolTest {
public static void main(String[] args) {
ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(10, true);
ArrayBlockingQueue<Runnable> runnableBlockingQueue = new ArrayBlockingQueue<Runnable>(10, true);
ThreadFactory threadFactory = new MyThreadFactory();
/*
ThreadPoolExecutor.AbortPolicy ThreadPoolExecutor 默认策略 直接抛出java.util.concurrent.RejectedExecutionException异常
ThreadPoolExecutor.DiscardPolicy 放弃当前任务,并且不会抛出任何异常
ThreadPoolExecutor.DiscardOldestPolicy 会将队列中最早添加的元素移除,再尝试添加,如果失败则按该策略不断重试
ThreadPoolExecutor.CallerRunsPolicy 由调用线程(提交任务的线程)处理该任务,如果调用线程是主线程,那么主线程会调用执行器中的execute方法来执行改任务
*/
ExecutorService executorServicePrd = new ThreadPoolExecutor(5,10, 1000,
TimeUnit.MILLISECONDS, runnableBlockingQueue, threadFactory, new ThreadPoolExecutor.AbortPolicy());
//生产者1
executorServicePrd.execute(new Runnable() {
@Override
public void run() {
while(true){
try {
int randomNum = new Random().nextInt(1000);
//插入元素,队列满时,不抛异常
boolean insertFlg = blockingQueue.offer(randomNum);
if(insertFlg){
System.out.println(StringFormatter.format("生产者:%s,新增产品%s。", Thread.currentThread().getName() , randomNum).getValue());
}else{
System.out.println(StringFormatter.format("生产者:%s,阻塞队列满了,生产失败!", Thread.currentThread().getName()).getValue());
}
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
}
}
});
//生产者2
executorServicePrd.execute(new Runnable() {
@Override
public void run() {
while(true){
try {
int randomNum = new Random().nextInt(1000);
//插入元素,队列满时,不抛异常
boolean insertFlg = blockingQueue.offer(randomNum);
if(insertFlg){
System.out.println(StringFormatter.format("生产者:%s,新增产品%s。", Thread.currentThread().getName() , randomNum).getValue());
}else{
System.out.println(StringFormatter.format("生产者:%s,阻塞队列满了,生产失败!", Thread.currentThread().getName()).getValue());
}
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
}
}
});
ExecutorService executorServiceConsummer = new ThreadPoolExecutor(5,10, 1000,
TimeUnit.MILLISECONDS, runnableBlockingQueue, threadFactory, new ThreadPoolExecutor.AbortPolicy());
//消费者1
executorServiceConsummer.execute(new Runnable() {
@Override
public void run() {
while(true){
try {
//取出元素,队列为空时,不抛异常
Integer headNum = blockingQueue.poll(100, TimeUnit.MILLISECONDS);
if(null!=headNum && headNum>0) {
System.out.println(StringFormatter.format("消费者:%s,消费掉产品%s。", Thread.currentThread().getName(), headNum).getValue());
}else{
System.out.println(StringFormatter.format("消费者:%s,阻塞队列为空,消费失败!",Thread.currentThread().getName()).getValue());
}
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
}
}
});
//消费者2
executorServiceConsummer.execute(new Runnable() {
@Override
public void run() {
while(true){
try {
//取出元素,队列为空时,不抛异常
Integer headNum = blockingQueue.poll(100, TimeUnit.MILLISECONDS);
if(null!=headNum && headNum>0) {
System.out.println(StringFormatter.format("消费者:%s,消费掉产品%s。", Thread.currentThread().getName(), headNum).getValue());
}else{
System.out.println(StringFormatter.format("消费者:%s,阻塞队列为空,消费失败!",Thread.currentThread().getName()).getValue());
}
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
}
});
}
}
备注:如果想查看生产者生产超额而生产失败,消费者消费完了而消费失败的两种极端情况,
修改生产者或者消费者线程的休眠时间即可。
运行结果:
三、
更复杂、更贴近现实的多线程阻塞队列实现,待续……