线程-生产者消费者
emmm…今天下午开始要利用java做一个爬虫为课设的数据库数据做准备,以前的爬虫设计用的是连接池爬虫池,但是效率不怎么样,所以补充线程上的一些知识,
先看这张图
大家都知道网络请求是一个非常耗时的一个问题,因为影响这个的因素很多,一个请求发送你可能要等好久才内得到io返回的数据,所以我们把程序设计成线程碎片化处理,分为3个部分,1就是网络请求部分,2数据解析部分,3数据持久化部分,1-2和2-3中我们用产品池差不多的概念作为连接,网络请求部分我们就可以多放几个线程去爬虫,2,3部分相比之下比第一部分耗时低的不是一个等级,这些也是我自己在学到Linux线程的时候收到的启发,并发的去处理问题,这样的效率会比串行的解决问题更高,
具体某个部分开几个线程和池子给多大,这个取决于最主要1、网速,2、运行内存,3、CPU等数据库原因,这个我也不好评估,各位有什么好建议可以评论区里面写,
下面我们来看线程中的生产者和消费者吧
1、我们先定义一个资源
/**
* 商品
*/
public class Product {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Product(String name){
this.name = name;
}
}
2、定义一个资源池
/**
* 商品池
*/
public class ProductPool {
/*
* 存储产品的集和
* 生产者生产
* 消费者消费产品
* */
private List<Product> products;
private int maxSize = 0;
public ProductPool(int maxSize) {
this.products = new LinkedList<>();
this.maxSize = maxSize;
}
/**
* 生产者讲商品存放到商品池
* @param product
*/
public synchronized void pust(Product product){
//判断商品池里面的商品是不是已经满了
if (products.size()==maxSize-1){
try {
//线程进入等待池里面
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
products.add(product);
//通知其他人可以消费了
this.notifyAll();
}
}
public synchronized Product pop(){
if (products.size() == 0){
try {
//进入等待队列中
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Product product = this.products.remove(0);
this.notifyAll();
return product;
}
public synchronized int size(){
return this.products.size();
}
}
3、生产者
/**
* 生产者
*/
public class Productor implements Runnable {
private ProductPool pool;
public Productor(ProductPool productPool){
this.pool = productPool;
}
@Override
public void run() {
while (true){
String productName = (int)(Math.random()*100)+":号产品";
pool.pust(new Product(productName));
System.out.println(Thread.currentThread().getName()+"线程生产了:"+productName+",剩余"+pool.size());
try {
//模拟生产者生产休眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4、消费者
/**
* 生产者
*/
public class Consumer implements Runnable {
private ProductPool pool;
public Consumer(ProductPool productPool){
this.pool = productPool;
}
@Override
public void run() {
while (true){
Product product = pool.pop();
String productName = product.getName();
System.out.println(Thread.currentThread().getName()+"线程消费了:"+productName);
try {
//模拟消费者休眠
Thread.sleep(70);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
5、运行
public class Program {
public static void main(String[] args) {
//实例化一个产品池对象
ProductPool productPool = new ProductPool(100);
Thread productor = new Thread(new Productor(productPool),"1号");
Thread productor3 = new Thread(new Productor(productPool),"3号");
productor.start();
productor3.start();
Thread consumer = new Thread(new Consumer(productPool),"2号");
consumer.start();
}
}
6、运行结果
3号线程生产了:98:号产品,剩余1
1号线程生产了:45:号产品,剩余1
2号线程消费了:45:号产品
2号线程消费了:98:号产品
1号线程生产了:84:号产品,剩余1
3号线程生产了:47:号产品,剩余2
2号线程消费了:84:号产品
3号线程生产了:47:号产品,剩余3
1号线程生产了:24:号产品,剩余3
2号线程消费了:47:号产品
2号线程消费了:47:号产品
3号线程生产了:97:号产品,剩余2
1号线程生产了:30:号产品,剩余3
2号线程消费了:24:号产品
3号线程生产了:89:号产品,剩余4
1号线程生产了:66:号产品,剩余4
2号线程消费了:97:号产品
2号线程消费了:30:号产品
3号线程生产了:96:号产品,剩余4
1号线程生产了:24:号产品,剩余4
ok再见