前言
在现在的大型分布式系统中,接口要处理的访问并发次数可能会十分的庞大,在Java中开发者应对这样的情况,在并发量较大的业务中都会使用线程池技术,以期达到增加接口的响应速度的效果!试想一件事本来只有一个人在累死累活的做,现在突然多出来二十个人一起做,那么时间会不会大大的缩短了。当然如果使用不当,人和人之间产生矛盾什么的,会不会反而起到负面作用呢?二十个人他们什么时候干活什么时候收工,是不是也要个统一的管理者呢?
案例
需要有线程基础,队列基础,线程池的基础!
使用线程池+队列做一个生产消费的案例!创建一个队列的统一资源管理类:
package com.study.store;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class TaskManager {
public static BlockingQueue<String> blockingQueue;
private TaskManager() {
blockingQueue = new LinkedBlockingQueue<String>();
}
private static volatile TaskManager instance;
public static TaskManager getInstance() {
if(instance == null) {
synchronized (TaskManager.class) {
if(instance == null) {
instance = new TaskManager();
}
}
}
return instance;
}
/**
* put -- 模拟任务生产 -- (场景应用在单线程下,put进有效的url地址)
*/
public static void produce(String url) throws InterruptedException {
blockingQueue.put(url);
}
/**
* take -- 模拟任务消费 -- (场景应用在多线程下,take取出有效的url并进行后期处理)
*/
public static String consume() throws InterruptedException {
return blockingQueue.take();
}
/**
* 获取队列的url数量 -- (如果这个值在10s内,等于0的话,将会终止所有任务 -- 生成线程 和 消费线程)
*/
public Integer getSize() {
return blockingQueue.size();
}
}
这个例子应该没什么好说的,dcl单例模式,生产与消费的方法!
生产者:
package com.study.store;
public class Producer implements Runnable {
private String name;
private String url;
public Producer(String name, String url, TaskManager taskManager) {
this.name = name;
this.url = url;
}
@Override
public void run() {
try {
while (true) {
// 生产url
System.out.println("生产者[" + name + "]:生产url --" + url);
TaskManager.produce(url);
// 休眠300ms -- 观看效果
Thread.sleep(3000);
}
} catch (InterruptedException ex) {
System.err.println("Producer Interrupted:" + ex.getMessage());
}
}
}
消费者:
package com.study.store;
public class Consumer implements Runnable {
private String name;
private TaskManager taskManager;
public Consumer(String name, TaskManager taskManager) {
this.name = name;
this.taskManager = taskManager;
}
@Override
public void run() {
while (true) {
// 消费url
try {
System.err.println(
"消费者[" + name + "]:消费url --" + TaskManager.consume() + "--剩余url容量:" + taskManager.getSize());
} catch (InterruptedException e) {
System.err.println("Consumer Interrupted :" + e.getMessage());
}
}
}
}
客户端:
创建两个生产者对象, 四个消费者,模拟生产者生产,消费者做即时消费:
package com.study.store;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Client {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
TaskManager manager = TaskManager.getInstance();
/**
* 来一个Java的线程池 CachedThreadPool会创建一个缓存区,将初始化的线程缓存起来 如果线程有可用的,就使用之前创建好的线程
* 如果没有可用的,就新创建线程 终止并且从缓存中移除已有60秒未被使用的线程
*/
ExecutorService service = Executors.newCachedThreadPool();
Producer producer1 = new Producer("生产者A", "http://www.baidu.com1", manager);
Producer producer2 = new Producer("生产者B", "http://www.baidu.com2", manager);
Consumer consumer1 = new Consumer("消费者1", manager);
Consumer consumer2 = new Consumer("消费者2", manager);
Consumer consumer3 = new Consumer("消费者3", manager);
Consumer consumer4 = new Consumer("消费者4", manager);
long start = System.currentTimeMillis();
for (int i = 0; i < 200; i++) {
// manager.produce("http://www.baidu.com-" + Integer.valueOf(i));
service.submit(producer1);
service.submit(producer2);
}
service.submit(consumer1);
service.submit(consumer2);
service.submit(consumer3);
service.submit(consumer4);
/**
* 来10打消费者 -- 模拟从队列管理器中取出url并进行资源下载
for (int i = 0; i < 10; i++) {
String name = "消费者:" + Integer.valueOf(i);
service.submit(new Consumer(name, manager));
}*/
while (true) {
Thread.sleep(1000 * 10);
// 主线程 每10秒检测一次,如果检测到任务队列里长时间没有内如put,就终止整个任务service
if (manager.getSize() == 0) {
service.shutdown();
break;
}
}
long end = System.currentTimeMillis();
System.err.println("下载任务完成!耗时:" + (end - start) + "");
}
}