Java常用类:ThreadPoolExecutor线程池

统信UOS服务器上,达梦DM8数据库安装避坑全记录(附大小写敏感设置) 本文详细介绍了在统信UOS服务器版上部署达梦DM8数据库的全过程,包括环境准备、安装流程、数据库实例初始化及关键参数配置,特别是大小写敏感设置的注意事项。提供了从系统配置到性能优化的完整指南,帮助用户避免常见问题,确保数据库稳定运行。 阅读详情

作为一个稀有的Java妹子,所写的所有博客都只是当作自己的笔记,留下证据自己之前是有用心学习的~哈哈哈哈(如果有不对的地方,也请大家指出,不要悄悄咪咪的不告诉我)

为什么需要线程池

首先举例一个业务场景,也是日常开发中经常会遇到的场景,手机短信验证业务。
短信验证在很多业务场景中都会遇到,比如验证码登录,短信提示余额不足等等。类似这种不影响主线程业务的,在访问量很大的情况下,就需要考虑使用多线程开发,避免访问量大时,造成接口阻塞。

那么有人会问了,既然需要多线程开发,那么在代码里直接创建线程来处理就好了呀。这种显示的在代码里创建线程的方式是不可取的,因为如果频繁的创建销毁线程,或者线程数太多,内存切换线程耗时久会造成服务器卡死。

所以,在不阻塞主线程的情况,使用另外的线程来处理某些业务时,就需要使用多线程,又因为频繁创建销毁线程十分耗时,线程池就应运而生啦。

线程池是什么

从字面上理解,就是装有线程的池子,这些线程可以处理特殊的业务,池子里有存放任务的队列,当队列里有任务时,线程会去队列里取任务执行,当队列为空时,线程就会等待。

结合业务场景分析,当需要发送短信时,就调用线程池,线程池会把发送短信的任务放到队列中(不准确,后面会细说,不是直接放队列),线程就会去队列中拿任务,执行发送短信,那么主线程就只管把发送短信的任务往线程池的队列中放,然后继续执行其他的逻辑。

贴一段生产环境的部分业务代码,支付订单成功后,在回调里处理跨境商品报关,当有很多用户支付成功时,这个方法就会被频繁调用,跨境商品报关就可以使用线程池来处理,这样接口的响应就会很快,因为不用等待短信处理的结果。

  /**
   * 完成支付 回调
   */
  public boolean compeletPay(PayOrderRes res) {
 	  // 销售单和收款单 推送金蝶
      k3OrderSellSender.send(order.getTransactionNo());
      //添加报关记录
      transCustomsService.addTransCustomsRecord(order.getTransactionNo());
      //跨境商品报关
      customsDeclareLogic
          .synchCustomsDeclare(order.getTransactionNo(), String.valueOf(order.getUserId()), 2);
}

源码解析

1.继承关系

ThreadPoolExecutor extends AbstractExecutorService
AbstractExecutorService implements ExecutorService
ExecutorService extends Executor

Executor是线程池的顶级接口,只有一个execute方法

public interface Executor {
    void execute(Runnable command);
}

ExecutorService继承了Executor,新增了许多方法

public interface ExecutorService extends Executor {
	void shutdown();
	List<Runnable> shutdownNow();
	boolean isShutdown();
	boolean isTerminated();
	<T> Future<T> submit(Callable<T> task);
}

2.成员变量

/**
线程池的状态
*/
//调用execute方法后,线程池就进行运行状态
private static final int RUNNING    = -1 << COUNT_BITS;
//调用shutdown方法后,线程就不再接收新的任务,正在执行的任务会执行完毕再真正关闭线程池
private static final int SHUTDOWN   =  0 << COUNT_BITS;
//调用shutdownNow方法后,线程不再接收新的任务,并且尝试关闭正在执行的线程
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
//当线程为shutdown/stop,且线程全部销毁后,线程池的状态就是终止
private static final int TERMINATED =  3 << COUNT_BITS;
/**
存放任务的队列
*/
private final BlockingQueue<Runnable> workQueue;
/**
存放线程的集合
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
/**
创建线程的工厂
*/
private volatile ThreadFactory threadFactory;
/**
队列里的任务满了时,拒绝处理的handler
*/
private volatile RejectedExecutionHandler handler;
/**
当前线程池中的线程数
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
/**
线程池核心大小,线程里可以有多少线程
*/
private volatile int corePoolSize;
/**
线程池最大线程数
*/
private volatile int maximumPoolSize;
/**
线程保持活跃的时间,当超过核心线程数,就会创建新的线程,这部分线程当不处理任务时,就会判断是否超过活跃时间,超过即销毁
*/
private volatile long keepAliveTime;

3.构造方法

//一共有四个
 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
     public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

构造方法初始化:核心线程数,最大线程数,活跃时间,时间单元,队列,线程工厂,拒绝处理handler

4.execute方法

//参数是线程,调用该方法就可以把线程放入线程池中,然后执行业务代码
public void execute(Runnable command) {
		//判断传进来的线程是否为空,是的话就抛出异常
        if (command == null)
            throw new NullPointerException();
        //获取当前线程池的线程数量
        int c = ctl.get();
        //与核心线程数比较
        if (workerCountOf(c) < corePoolSize) {
        	//如果小于核心线程数,则在线程池中创建线程
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //如果当前线程数大于核心线程数,则把线程放到队列中
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //如果当前线程数大于核心线程数,队列又满了,那么就拒绝处理
        else if (!addWorker(command, false))
            reject(command);
    }

//当线程池中的线程数<核心线程数时,创建worker,即线程
private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        //比较线程池的数量与核心线程数量,判断线程池队列是否为空,线程池的状态是否为RUNNING等等
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
			
            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                 //将线程池中的线程数+1
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
		
		//当通过检验后,创建线程
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
        	//使用worker创建线程,Worker是ThreadPoolExecutor的内部类,专门用来创建线程,管理线程的
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());
					//拿到锁后再次判断线程池的状态
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        //添加线程
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                	//启动线程,注意这里的start会运行Worker里的Run方法,后面有介绍
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

//内部类Worker
private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        private static final long serialVersionUID = 6138294804551838833L;
        final Thread thread;
        Runnable firstTask;
        volatile long completedTasks;
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }
        
        public void run() {
        	//看下这个方法
            runWorker(this);
        }
    }

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        //这个task就是调用execute时传入的线程,这个线程里的run方法里才是业务逻辑代码
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
        	//判断队列是否为空,不为空则从队列中获取任务
            while (task != null || (task = getTask()) != null) {
                w.lock();
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                    	//运行业务线程
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }
//从队列获取任务
private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
            	//获取任务
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

5.其他方法

1.shutdown()

public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }
private void checkShutdownAccess() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkPermission(shutdownPerm);
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                for (Worker w : workers)
                    security.checkAccess(w.thread);
            } finally {
                mainLock.unlock();
            }
        }
    }
private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

6.Executor和Executors的区别

Executor是线程池的顶级接口,Executors提供了一些创建线程池的方法

public class Executors {
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }
    ......
}

举例

我直接贴生产环境的业务代码出来,look look

public class CustomsDeclareLogic {
  @Autowired
  EpayService epayService;
  @Autowired
  AlipayService alipayService;
  @Autowired
  WxPayService wxPayService;


  public class CustomsDeclareThread implements Runnable {

    private String transactionNo;
    private String userId;
    /**
    * 1新增报关记录,2修改报关记录
    */
    private Integer action;

    public CustomsDeclareThread(String transactionNo, String userId, Integer action) {
      this.transactionNo = transactionNo;
      this.userId = userId;
      this.action = action;
    }

    @Override
    public void run() {
      try {
      	//处理业务逻辑
        declareOrder(transactionNo,userId,action);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    public String getTransactionNo() {
      return transactionNo;
    }

    public void setTransactionNo(String transactionNo) {
      this.transactionNo = transactionNo;
    }

    public String getUserId() {
      return userId;
    }

    public void setUserId(String userId) {
      this.userId = userId;
    }
  }

//创建线程池
  private static ExecutorService CUSTOMSDECLARE_THREAD_POOL = new ThreadPoolExecutor(
      2, 10, 5 * 60L,
      TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
      new ThreadFactory() {
        private final AtomicInteger threadNumber = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable r) {
          return new Thread(r,
              "schedule-pool-overseas-customsDeclare" + threadNumber.getAndIncrement());
        }
      }
  );

  public void synchCustomsDeclare(String transactionNo, String userId, Integer action) {
  	//调用execute时,将业务线程放入
    CUSTOMSDECLARE_THREAD_POOL
        .execute(new CustomsDeclareThread(transactionNo, userId, action));
  }

  /**
   *
   * @param transactionNo 支付单号
   * @param userId  用户id
   * @param action 1新增报关记录,2修改报关记录
   */
  public void  declareOrder(String transactionNo,String userId,Integer action){
    System.out.println(transactionNo + "+++++" + userId);
    List<PTbOrder> orderList = orderService.selectOrderByTransactionNo(transactionNo, userId);
    PTbTransaction tbTransaction = transactionService
        .selectTransactionByTransactionNo(transactionNo);
    for (PTbOrder pTbOrder : orderList) {
      String warehouseType = pTbOrder.getWarehouseType();
      if ("INBONDED".equals(warehouseType)) {
        //报关方式判断
        if ("EPAY_WX_APP".equals(tbTransaction.getPayMethod()) || "EPAY_WX_WEB"
            .equals(tbTransaction.getPayMethod())) {//网易支付报关
          log.info("++++网易支付跨境商品报关++++start" + transactionNo);
          epayService.customsDeclare(tbTransaction, pTbOrder, String.valueOf(action), true,
              tbTransaction.getPayMethod());
        } else if ("ALIPAY_GUOJI".equals(tbTransaction.getPayMethod())) {//国际支付宝报关
          log.info("++++支付宝支付跨境商品报关++++start" + transactionNo);
          alipayService
              .customsDeclare(tbTransaction, pTbOrder, true, tbTransaction.getPayMethod(),
                  action, false);
        } else if ("WXPAY".equals(tbTransaction.getPayMethod()) || "WXPAY_APP".equals(tbTransaction.getPayMethod()) || "WXLITE".equals(tbTransaction.getPayMethod())) {
          log.info("+++++原生微信支付报关+++++start");
          wxPayService.customsDeclare(tbTransaction, pTbOrder, true, tbTransaction.getPayMethod(),action);
        }
      }
    }
  }

}

文章开篇举例跨境报关的,就是调用的这个类的synchCustomsDeclare方法,在该方法中执行线程池的execute

图解B+树的插入过程 B+ 树在现代数据库中很常见,如果我们了解它,在工作中可能对性能优化会有更好的帮助! 最近我一直在思考 B+ 树的高度是由什么决定的。知道我了解了 B+ 树的插入过程,才有一种恍然大悟的感觉! 网上的一些资料杂乱无章,不同的数据库可能还有对 B+ 树有不同的实现。但是万变不离其宗,B+ 树的定义,大致如下所示: 总结一下,B+ 树有下面 5 个重要的特点。 B+ 树包含 2 种类型的结点: 内部结点(也称索引结点)和叶子结点。 根结点本身即可以是内部结点,也可以是叶子结点。 根结点的关键字个数最 阅读详情

相关推荐

MR2数据集实战:5步搞定多模态谣言检测模型训练(附完整代码)

本文详细介绍了如何使用MR2多模态数据集构建高精度谣言检测系统,涵盖环境配置、数据准备、多模态特征工程、模型架构设计、训练调优及部署优化等5个关键步骤。通过双线性融合技术处理文本、图像和网页三模态数据,解决特征对齐和模态冲突等工程难题,并提供完整代码实现和性能优化方案。

weixin_42657024的博客 238

java 线程池 threadpoolexecutor_线程池ThreadPoolExecutor的使用方法

方法我们通过继承Thread类和实现runnable接口或者callable接口三种方式实现。继承Thread类实际上也是实现了runnable接口,被继承的类主要是实现run()方法,通过start()方法调用。而callable接口是属于Executor对比与Runnable接口功能的区别是:(1).Callable可以在任务结束后提供一个返回值,Runnable没有这个功能(2).Calla...

weixin_30824577的博客 2559

FPGA时序约束--实战篇(读懂Vivado时序报告)

本文将详细介绍如何读懂Vivado时序报告,包括报告的基本结构和如何分析报告。

mengzaishenqiu的博客 1万+

ThreadPoolExecutor详解

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> ...

爱宝贝丶的博客 143

ROS基础(一)——命令行代码(以小乌龟程序为例)

ROS学习(一)——命令行代码(以小乌龟程序为例)1 基础命令行语句1.1 roscore1.2 rqt_graph(显示系统计算图)1.3 rosnode(显示所有节点相关信息)1.4 rostopic(和话题相关)2 服务类型指令rosservice同时存在两只海龟3 指令记录 1 基础命令行语句 从大二四旋翼无人机编队后就没再接触过ROS了,最近由于科研任务需要重新捡起来,打算系统学一下!学习过程参考古月居老师的视频,有兴趣的同学可以去[BliBli]学习。 学习平台:Ubuntu 18.04 硬件

北理自动化小白 6262

关于笔记本测试的面试准备 2021-10-11

** 关于笔记本测试的面试准备 ** 一、根据JD分析,工作内容以软测为主,硬件知识需要了解一点。 以下几个问题为主要: 1.了解VGA、audio、wlan、bt、TP 、camera等driver,BIOS和image测试。 2.了解性能测试工具?压力测试相关设置? 3.了解preload流程? 二、解决 VGA: video graphics array ——笔记本上外接显示器的接口。 【VGA接口兼容性更强,但是不支持高分辨率。 支持高分辨率:HDMI、DIV、TP】 bt【Bluetooth

xw_009的博客 1865

java多线程——ThreadPoolExecutor线程池及实现原理

线程池的核心类ThreadPoolExecutor: 线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。 ThreadPoolExecutor继承了AbstractExecutorSer...

zhoushimiao1990的博客 699

完美解决unknown failed to transfer from http://0.0.0.0/ during a previous attempt的错误

完美解决unknown failed to transfer from http://0.0.0.0/ during a previous attempt的错误

念兮为美 2279

java线程池使用详解ThreadPoolExecutor使用示例

一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 1) 任务(Runnable /Callable) 2) 任务的执行(Executor) 3) 异步计算的结果(Future) 2.3 Executor 框架的使用示意图 三 (重要)ThreadPoolExecutor 类简单介绍 3.1 ThreadPoolExecutor 类分析 3.2 推荐使用 ThreadPoolExecutor 构造函数创建线程池 四 ..

xu_yong_lin的博客 5万+

OpenCV计算机视觉实战(3)——计算机图像处理基础

本文全面介绍了计算机视觉和数字图像处理的基础知识。从最基本的像素概念入手,详细讲解了图像在计算机中的表示方式,包括RGB、CMYK等色彩空间的工作原理及其应用场景。还系统分析了常见图像和视频文件格式的特点,梳理了计算机图像处理技术的发展历程,并重点介绍了OpenCV这一强大的开源计算机视觉库的功能与应用领域。

qq_30167691的博客 1738

120、ISP 驱动架构解析:从 V4L2 请求到 ISP 硬件的配置下发流程

本文以实际案例解析ISP驱动架构的V4L2到硬件配置下发流程。作者通过一个因内存共享导致画面闪烁的bug案例,详细剖析了用户空间参数通过V4L2结构体传递、驱动层拆包与硬件寄存器映射、时序同步机制等关键环节。特别强调深拷贝、dirty flag增量更新、shadow register等实现要点,并给出多路并发隔离、寄存器写入失败等典型问题的排查方法。文章建议开发者深入理解参数到寄存器的转换过程,推荐通过debugfs实时监控寄存器状态,避免过度依赖自动调试工具。全文以实践为导向,对ISP驱动开发具有直接指导

sundong_81的博客 159

Java线程池ThreadPoolExecutor详细介绍与使用

Java线程池ThreadPoolExecutor详细介绍与使用

qq_27480007的博客 1万+

Python爬虫实战:全网政府招标信息采集与整合

本文详细介绍了如何使用Python构建一个完整的政府招标信息爬虫系统,涵盖了从数据采集、解析、存储到质量监控的全流程。多源采集:支持多个地方政府网站的同时采集智能解析:自动适应不同网站结构,智能提取关键信息异步高效:使用异步编程提高采集效率反爬应对:内置多种反爬虫应对策略数据质量:完善的数据清洗和质量监控机制易于扩展:模块化设计,便于添加新的数据源。

2201_76125261的博客 1380

JAVA多线程之ThreadPoolExecutor创建线程池

线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。说明:Executors 返回的线程池对象的弊端如下:FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

lqr666的博客 4003

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Java线程池之ThreadPoolExecutor

(1)自己创建一个单线程串行执行任务,如果任务执行失败而终止那么没有任何补救措施,而线程池还会新建一个线程,保证池的正常工作。(1)线程池中刚开始没有线程,当一个任务提交给线程池后,线程池会创建一个新线程来执行任务。整个线程池表现为线程数会根据任务量不断增长,没有上限,当任务执行完毕,空闲。,意味着:全部都是救急线程(60s 后可以回收),救急线程可以无限创建。时,会放入无界队列排队。(3)如果队列选择了有界队列,那么任务超过了队列大小时,会创建。并没有线程空闲,这时再加入任务,新加的任务会被加入。

YouPromise的博客 1510

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Java并发编程:ThreadPoolExecutor常用线程池

目录 线程池的分类 常用线程池(ThreadPoolExecutor)示例 CachedThreadPool FixedThreadPool SingleThreadExecutor ThreadPoolExecutor类分析 三种线程池(返回ThreadPoolExecutor)构造方法 ThreadPoolExecutor中的成员变量 三种线程池(返回ThreadPoolEx...

Jodness' Blogs 1万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Java 线程池 ThreadPoolExecutor

Java 线程池 ThreadPoolExecutor

26857259 1002

Java之线程池:线程池常用类、接口;线程池执行流程,配置参数,分类

Java线程池

HakerDONG的博客 1232

Java 并发之线程池 ThreadPoolExecutor

顶层的接口,用来执行提交的 Runnable 任务。这个接口提供了一种将任务提交和任务运行机制(包括线程的使用、调度等)解耦的方式。总而言之,它是一个顶层接口。

xlh1191860939的博客 832

java线程池ThreadPoolExecutor详解及使用

java线程池ThreadPoolExecutor的使用 在日常开发中我们经常会使用多线程,但是当线程数量达到一定程度时,频繁的创建线程、执行任务、销毁线程就会造成资源的浪费和性能的开销,那么这个时候就要考虑使用线程池了,它可以很好的避免这个问题,尤其是程序中需要创建大量的生存周期很短的线程时,更应该考虑使用线程池。 线程池的概念 线程池(ThreadPool),简单的说,它就是一个装有线程的池子,我们只需把任务(多线程执行的内容)交给线程池来处理,和数据库连接池、Http连接池的概念差不多的,通过维护

weixin_44178366的博客 4616

Java线程池详解:ThreadPoolExecutor、Executors

在操作系统中,线程是一个非常重要的资源,频繁创建和销毁大量线程会大大降低系统性能。Java线程池原理类似于数据库连接池,目的就是帮助我们实现线程复用,减少频繁创建和销毁线程。ThreadPoolExecutorThreadPoolExecutor是线程池的核心类。首先看一下如何创建一个ThreadPoolExecutor。下面是ThreadPoolExecutor常用的一个构造方法:ThreadPo

叉叉哥的BLOG 1万+

Java 线程池ThreadPoolExecutor

 Java线程池ThreadPoolExecutor. JDK1.5开始关于多线程加了很多特性。如:ConcurrentHashMap:放弃使用公用锁同步每一个方法,使用了更细化的锁机制,分离锁。对于大数据量的HashMap同步操作效率有了较大提升。CopyOnWriteArrayList:是同步Lis

abing37的专栏 2万+

Java线程池ThreadPoolExecutor

核心线程数,也就是线程池创建时持有的线程个数,核心线程默认情况下就算空闲也不会被销毁,可以通过设置`allowCoreThreadTimeOut`为`true`允许空闲的核心线程销毁

fggdgh的博客 1427

Java线程池:ThreadPoolExecutor原理解析

本文介绍了线程池的基本概念、主要参数、工作流程,以及 execute() 方法的源码分析,此外,还讨论了在实际应用中可能遇到的陷阱和问题。

u014800975的博客 1231

【并发编程】JUC常用类以及线程池

并发编程中JUC常用类以及线程池相关知识整理总结!

小谷同学的博客 1235

Java 线程池ThreadPoolExecutor源码解读

线程池与其说他是复用Thread,不如说他是不断地向Thread中填充新的Runnable,然后调用run,减少了创建Thread的开销。这个是老生常谈的实现方法了,继承Thread的时候需要实现run,如果直接调用run的话是无法开启线程的。如果阻塞队列都放慢了,就会看非核心线程是否到了最大的线程数,如果达到了最大线程,就会执行拒绝策略。总的来说addWorker除了进行Worker的构建和添加到Workers之外,还进行了Worker中线程的启动,这块是真正执行我们定义的逻辑的地方。

allen_xu_2012_new的博客 973
上一篇: 集合的区别、适用场景以及如何排序(List,Map,Set)
下一篇: Java常用类:Collections详解
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值