线程的创建与线程池ThreadPoolExecutor,Executors

Executors与ThreadPoolExecutor(阿里发布的 Java开发手册中强制线程池不允许使用 Executors 去创建) 最近阿里发布的 Java开发手册中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险 Executors利用工厂模式向我们提供了4种线程池实现方式,但是并不推荐使用,原因是使用Executors创建线程池不会传入这个参数而使用默认值所以我们常常忽略这一参数,而且默认使用的参 阅读详情

                    线程的创建与线程池及线程池工具类

1.线程的创建方式

1.1继承Thread类重写run方法

public class Test {

	public static void main(String[] args) {
	Thread thread = new MyThread();
	thread.setName("mythread001");
	thread.start();  
	}

	
}
class MyThread extends Thread{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName() + ",running ....");
	}
}

1.2实现Runnable接口

public class Test {

	public static void main(String[] args) {
	Thread thread = new Thread(new MyRunnable());
	thread.setName("myRunnable001");
	thread.start();  
	}
}
class MyRunnable implements Runnable{

	@Override
	public void run() {
		System.out.println("my runnable...");
	}
}

    其实以上两种方式本质上是一样的,都是重写了接口Runnable的run方法,因为Thread类实现了Runnable接口。Runnable接口是JDK1.0提供的,在java.lang包下,但是Runnable接口的run方法有的场景下并不合适,比如不能返回运算结果和抛出检查异常,这时我们可以使用JDK1.5提供的在java.util.concurrent包下的Callable接口:

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

1.3Callable接口类型的线程创建

因为该接口可以返回一个结果,所以我们需要获取返回结果,这时系统提供了一个Future接口用于获取返回的结果,但是该接口代表的是一个异步计算的结果,所以我们需要等到计算完成时才能获取结果,否则就会一直阻塞直到结果返回。Future接口内的方法如下:

 /**
     * Attempts to cancel execution of this task.  This attempt will
     * fail if the task has already completed, has already been cancelled,
     * or could not be cancelled for some other reason. If successful,
     * and this task has not started when {@code cancel} is called,
     * this task should never run.  If the task has already started,
     * then the {@code mayInterruptIfRunning} parameter determines
     * whether the thread executing this task should be interrupted in
     * an attempt to stop the task.
     *
     * <p>After this method returns, subsequent calls to {@link #isDone} will
     * always return {@code true}.  Subsequent calls to {@link #isCancelled}
     * will always return {@code true} if this method returned {@code true}.
     *
     * @param mayInterruptIfRunning {@code true} if the thread executing this
     * task should be interrupted; otherwise, in-progress tasks are allowed
     * to complete
     * @return {@code false} if the task could not be cancelled,
     * typically because it has already completed normally;
     * {@code true} otherwise
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * Returns {@code true} if this task was cancelled before it completed
     * normally.
     *
     * @return {@code true} if this task was cancelled before it completed
     */
    boolean isCancelled();

    /**
     * Returns {@code true} if this task completed.
     *
     * Completion may be due to normal termination, an exception, or
     * cancellation -- in all of these cases, this method will return
     * {@code true}.
     *
     * @return {@code true} if this task completed
     */
    boolean isDone();

    /**
     * Waits if necessary for the computation to complete, and then
     * retrieves its result.
     *
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     *
     * @param timeout the maximum time to wait
     * @param unit the time unit of the timeout argument
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     * @throws TimeoutException if the wait timed out
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

所以我们获取结果要在调用isDone()方法返回true时才能调用get()方法。该接口有一个系统提供的实现类FutureTask,FutureTask类实现了RunnableFuture<V>,RunnableFuture<V>接口继承了Runnable, Future<V>两个接口。FutureTask中实现的Runnable中的run方法调用了Callable接口中的call方法。所以创建Callable接口的线程的方法与Runnable类似:

public class Test {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<String> future = new FutureTask<String>(new Callable<String>() {

			@Override
			public String call() throws Exception {
				return "hello";
			}
		});

		Thread thread = new Thread(future);
		thread.setName("myCallable001");
		thread.start();
		while (!future.isDone()) {
			try {
				System.out.println("myCallable001 is not done");
				//等待线程运行结束
				Thread.currentThread().sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		String result = future.get();
		System.out.println("result : " + result);
	}
}

运行结果如图:

2.线程池

        线程的创建我们已经知道了,但是需要让线程启动运行我们需要调用start()方法,该方法会为线程准备必要的系统资源,比如线程的栈内存,程序计数器和本地栈等,所以一个线程是需要消耗系统资源的,也是耗时的。为了降低系统资源的消耗和提高系统的运行效率我们需要对线程复用,就像数据库连接池一样,使用线程池技术,来达到这个目的。JDK为了我们提供了ThreadPoolExecutor类,接下来我们学习下这个线程池类:

2.1Executor

    该接口源码如下:

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

该接口声明了一个方法,void execute(Runnable command);用来执行一个线程。

2.2ExecutorService

    该接口继承自Executor,并声明了以下方法:

该接口种的方法更加实用,shutdown()方法与shutdownNow()方法用于停掉线程池,源码中写了如下的例子:

    首先调用shutdown()阻止新的任务提交到线程池,调用awaitTermination等待正在执行的线程执行完毕,或者超时或者被打断执行,然后再调用shutdownNow()取消当前正在执行的任务。其他的方法见名知意。

2.3AbstractExecutorService

    该抽象类实现了ExecutorService接口,其方法如图:

这些方法中要说的就是<T> RunnableFuture<T> newTaskFor(Runnable runnable, T value),该方法将Runnable接口的任务转换为Callable相关的FutureTask<T>。其代码实现如图:

在FutureTask<T>中的构造方法源码如下:

再到Executors.callable(runnable, result)查看源码如下:

2.4ThreadPoolExecutor

    构造函数

    线程池实现类,我们先看该类的核心构造函数:

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.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

参数:corePoolSize。the number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set。线程池中保持的线程数量,尽管这些线程是空闲的,除非设置allowCoreThreadTimeOut参数为true,则在空闲时间超过keepAliveTime时,会被终止掉。allowCoreThreadTimeOut默认为false。

参数:maximumPoolSize。线程池中允许的最大线程数量。

参数:keepAliveTime。保持活跃的时间,也就是当线程池中的线程数量超过corePoolSize时,这些超量的线程在等待被新任务使用前的最大等待时间,超过找个时间就要被终止掉了。

参数:unit。保持活跃时间的单位。可选为:NANOSECONDS,MICROSECONDS,MILLISECONDS,SECONDS,MINUTES,HOURS,DAYS等。

参数:workQueue。工作队列。这队列用来保持那些execute()方法提交的还没有执行的任务。常用的队列有SynchronousQueue,LinkedBlockingQueue,ArrayBlockingQueue。一般我们需要根据自己的实际业务需求选择合适的工作队列。

SynchronousQueue:直接传递。对于一个好的默认的工作队列选择是SynchronousQueue,该队列传递任务到线程而不持有它们。在这一点上,试图向该队列压入一个任务,如果没有可用的线程立刻运行任务,那么就会入列失败,所以一个新的线程就会被创建。当处理那些内部依赖的任务集合时,这个选择可以避免锁住。直接接传递通常需要无边界的最大线程数来避免新提交任务被拒绝处理。当任务以平均快于被处理的速度提交到线程池时,它依次地确认无边界线程增长的可能性;

LinkedBlockingQueue:无界队列。没有预先定义容量的无界队列,在核心线程数都繁忙的时候会使新提交的任务在队列中等待被执行,所以将不会创建更多的线程,因此,最大线程数的值将不起作用。当每个任务之间是相互独立的时比较适合该队列,所以任务之间不能互相影响执行。例如,在一个WEB页面服务器,当平滑的出现短暂的请求爆发时这个类型的队列是非常有用的,当任务以快于平均处理速度被提交时该队列会确认无边界队列增长的可能性。

ArrayBlockingQueue:有界阻塞队列,遵循FIFO原则,一旦创建容量不能改变,当向一个已经满了的该队列中添加元素和向一个已经为空的该队列取出元素都会导致阻塞;当线程池使用有限的最大线程数时该队列可以帮助保护资源枯竭,但它更难协调和控制。队列大小和最大线程数在性能上可以互相交换:使用大队列和小线程池会降低CPU使用和OS资源与上下文切换开销,但会导致人为降低吞吐量,如果任务频繁阻塞,系统的线程调度时间会超过我们的允许值;如果使用小队列大池,这将会使CPU较为繁忙但会出现难以接受的调度开销,这也会导致降低吞吐量。

参数:threadFactory。线程工厂。当线程池需要创建线程的时候用来创建线程。默认是Executors类的静态内部类DefaultThreadFactory。源码如下:

static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

主要是设置了一些守护性和优先级等属性。

参数:handler。拒绝执行处理器。当线程的数量已经到了边界值,并且workQueue中任务也达到最大值,此时需要使用处理器处理多余的任务。该参数有四个值,分别是CallerRunsPolicy,AbortPolicy,DiscardPolicy,DiscardOldestPolicy。这四个处理器是线程池的内部类,都实现了RejectedExecutionHandler接口。

CallerRunsPolicy:在调用execut方法的调用线程中直接执行线程池拒绝的任务;

AbortPolicy:以抛出一个RejectedExecutionException的方式处理拒绝执行的任务;

DiscardPolicy:以直接忽略的方式处理拒绝执行的任务;

DiscardOldestPolicy:忽略掉最老的没有处理的拒绝任务,然后继续尝试执行execute方法,知道线程池关闭,那么放弃找个任务。

线程的管理

    首先看看该类中的注释中是如何解释线程池怎么管理线程的:

When a new task is submitted in method {@link #execute(Runnable)},
 * and fewer than corePoolSize threads are running, a new thread is
 * created to handle the request, even if other worker threads are
 * idle.  If there are more than corePoolSize but less than
 * maximumPoolSize threads running, a new thread will be created only
 * if the queue is full.  By setting corePoolSize and maximumPoolSize
 * the same, you create a fixed-size thread pool. By setting
 * maximumPoolSize to an essentially unbounded value such as {@code
 * Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary
 * number of concurrent tasks. Most typically, core and maximum pool
 * sizes are set only upon construction, but they may also be changed
 * dynamically using {@link #setCorePoolSize} and {@link
 * #setMaximumPoolSize}. 

       当一个任务通过execute(Runnable)方法被提交时,并且有少于核心线程数的线程正在运行,那么一个新的线程会被创建去处理请求,即使其它的线程正在空闲;如果有多余核心线程数但小于最大线程数的线程在运行,如果任务队列没有满,则将任务压入任务队列等待执行完任务的线程去处理,如果满了则创建新的线程处理该任务;如果正在运行的线程数大于最大线程数,则需要根据拒绝执行处理器的不同进行处理。通过将核心线程数与最大线程数设置为相同的值,你可以创建一个固定大小的线程池。通过设置最大线程数为一个基本上是无边界的值例如Integer.MAX_VALUE,你允许线程池容纳任意数量的并发任务。通常,核心线程数和最大线程数是通过构造函数设置的,但是他们也可以通过使用setCorePoolSize和setMaximumPoolSize动态的改变。

    验证如下:

    新建一个线程池,代码如下:

public class Main {

	public static void main(String[] args) throws Exception {

		// 有界队列
		BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(5);
		// 放弃拒绝的任务并抛出异常
		RejectedExecutionHandler abortPolicyHandler = new ThreadPoolExecutor.AbortPolicy();
		RejectedExecutionHandler discardPolicyHandler = new ThreadPoolExecutor.DiscardPolicy();
		ThreadPoolExecutor threadPool = 
				new ThreadPoolExecutor(5, 10, 30, TimeUnit.SECONDS, workQueue, discardPolicyHandler);
		long start = System.currentTimeMillis();
		for (int i = 0; i < 40; i++) {
			threadPool.execute(new MyTask());
			System.out.println("核心线程数" + threadPool.getCorePoolSize());
			System.out.println("最大线程数" + threadPool.getMaximumPoolSize());
			System.out.println("线程池数" + threadPool.getPoolSize());
			System.out.println("队列任务数" + threadPool.getQueue().size());
			System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
		}
		
		System.out.println(System.currentTimeMillis()-start);
		threadPool.shutdown();
		if (threadPool.awaitTermination(6, TimeUnit.SECONDS)) {
			threadPool.shutdownNow();
		}
	}

}

class MyTask implements Runnable {

	@Override
	public void run() {
		try {
			Thread.currentThread().sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ", hello");
	}

}

运行部分日志如下: 

核心线程数5
最大线程数10
线程池数1
队列任务数0
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数2
队列任务数0
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数3
队列任务数0
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数4
队列任务数0
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数5
队列任务数0
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数5
队列任务数1
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数5
队列任务数2
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数5
队列任务数3
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数5
队列任务数4
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数5
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数6
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数7
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数8
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数9
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
核心线程数5
最大线程数10
线程池数10
队列任务数5
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

通过以上日志分析可以验证线程的创建过程是正确的。

初始化核心线程数

       默认的核心线程只有在任务被提交的时候才会创建和启动,但是当我们的工作队列是一个非空队列的时候我们需要在线程池启动的时候就有核心线程可用,这时候我们可以使用prestartCoreThread()方法和prestartAllCoreThreads()方法。我们只需要在线程池被创建后根据自己的需求调用其中的方法即可。

:

Executors

    因为ThreadPoolExecutor线程池类创建线程较为麻烦,需要设置的参数比较多。线程池工具类,提供了一些工厂方法或者实用方法用来创建或者使用线程池,使我们更加方便快捷的创建和使用线程池。

  1.     创建固定线程数的线程池

2.创建单线程的线程池是固定线程的线程池的特例。

3.创建缓存线程池,该线程池中的线程会随着任务的提交不断被创建,也就是as needed。但是先前创建的可用的线程仍然可以被复用。当线程空闲时间超过60秒后会被终止和从缓存中移除。这种线程池适合那些有大量的短执行时间的异步任务。

当然还可以创建一些定时任务线程池。

为什么阿里巴巴创建线程池禁用Executors,而是通过ThreadPoolExecutor? 写在前面 通过阅读本篇文章你将了解到: 线程池的定义 Executors创建线程池的几种方式 ThreadPoolExecutor对象 线程池执行任务逻辑和线程池参数的关系 Executors创建返回ThreadPoolExecutor对象 OOM异常测试 如何定义线程池参数 如果只想知道原因可以直接拉到总结那~ 开始之前,记得点赞收藏加关注哦 ,需要下载PDF版本和获取更多知识点、面试题的朋友可以点一点下方链接免费领取 链接:点这里!!! 799215493 暗号:优快云 线程池的定义 阅读详情

相关推荐

ESP32固定翼航模硬件设计与飞行力学解析

固定翼无人机是嵌入式控制与空气动力学交叉实践的经典载体,其飞行稳定性本质源于重心、气动中心与控制面的物理耦合关系。理解静稳定度(Static Margin)、升力系数调控、偏航力矩生成等基础原理,是实现可靠姿态控制的前提。在低成本工程约束下,材料刚度、结构弹性与电机-驱动协同设计共同决定了系统动态响应边界。ESP32平台凭借高精度PWM、低功耗双模无线及丰富GPIO,成为教学级航模开发的理想主控;而魔术贴基板、可调电池配重、柔性尾翼等创新结构,则将抽象的飞行力学概念转化为可测量、可调试的实体对象,广泛应用于

weixin_29859471的博客 365

线程池创建线程

定义:使用池化技术来管理和使用现成的技术,就叫做线程池 线程池的优势 总体来说,线程池有如下的优势: (1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 (2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。 (3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。 线程池创建线程的7种方式1.创建固定个数的线程池设置线程的名称和优先级2.创建带缓存的线程池3.创建可以执行定时

guyihanzb的博客 4649

ctx->cvdl->cuvidGetDecoderCaps(&ctx->caps8) failed -> CUDA_ERROR_DEINITIALIZED: driver shutting down

ffplay -vcodec h264_cuvid sample_720p-2.h264 [quantum6@freeswitch freeswitch]$ ffplay -vcodec h264_cuvid sample_720p-2.h264 ffplay version 4.3.1 Copyright (c) 2003-2020 the FFmpeg developers built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-44) .

柳鲲鹏 2404

线程的创建(线程池)

线程的创建(线程池)

weixin_44251806的博客 3421

智能安防摄像头埋点实践:用户行为与设备状态的闭环监控(含AI事件)

智能安防摄像头埋点闭环体系设计及应用实践 摘要: 本文系统阐述了智能安防摄像头埋点闭环体系的设计与实践。首先分析了传统埋点的不足及闭环埋点的价值,提出由用户行为埋点、设备状态埋点和AI事件埋点构成的三维埋点体系框架。详细介绍了闭环监控的四大流程:数据采集、汇聚清洗、分析建模和智能决策。通过误报优化、个性化策略等案例展示了AI事件闭环的实际应用价值,并探讨了隐私合规、性能优化等关键挑战的解决思路。最后展望了端侧AI增强、预测型埋点等未来发展趋势。该体系实现了从数据采集到业务决策的完整闭环,有效提升了AI模型性

专注智能硬件软硬件产品经理成长与实战,分享从需求定义到量产落地的真实日记。涵盖IoT趋势洞察、研发协作经验、产品方法论与工具箱,用轻松有趣的“汪式”视角,陪伴产品经理成长、避坑与升级。 1046

软件项目成本控制实战:从COCOMO模型到挣值分析的5个关键步骤

本文详细介绍了软件项目成本控制的5个关键步骤,从COCOMO模型估算到挣值分析预警,帮助中小型团队精准管理预算。通过简化COCOMO II的有机模式、动态建立成本基准、轻量化挣值分析等方法,项目经理可以有效应对预算超支和进度延误问题,提升项目成功率。

weixin_30733003的博客 227

ThreadPoolExecutor创建线程池

ThreadPoolExecutor是Java中用于管理线程池的类,它提供了一个灵活且可配置的线程池,可以有效地执行并管理多个任务。

CNDN_Web的博客 2974

h5支付不能打开支付宝 ios_iOS支付宝H5支付无法返回APP解决方案

本文前大段在讲楼主是如何解决这个问题的,以及中间遇到的麻烦。赶时间的同学可以直接看最后的 最终解决方案。在讨论之前,我们先看看官方文档上的一句话:注意:在iOS系统中,唤起支付宝App支付完成后,不会自动回到浏览器或商户APP。用户可手工切回到浏览器或商户APP;支付宝H5收银台会自动跳转回商户return_url指定的页面。what? 官方直接跟我们说GG了?楼主不甘心,还是想尝试一下。借鉴之前...

weixin_39864101的博客 854

多线程之使用线程池创建线程

1.使用线程池的优点 1.减少资源的消耗。重复利用已经创建的线程,避免频繁的创造和销毁线程,减少消耗。 2.提高响应速度。当执行任务时,不需要去创建线程再来执行,只要调动现有的线程来执行即可。 3.提高了线程的管理性。线程是稀缺资源,使用线程池可以进行统一的分配、调优和监控。 2.创建线程池的两种方案 1.通过Executors创建,它提供了四种线程池: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixe

m0_49562228的博客 5556

前导0预测(Leading-Zero Anticipator,LZA)

前导0预测(Leading-Zero Anticipator,LZA) 浮点加法在完成之后会进行尾数规格化移位,而在进行尾数加法时,可以使用前导0预测(Leading-Zero Anticipator,LZA)同时计算移位,前导0预测只发生在一个正数加上一个负数的情况下,电路图如图1所示。 图1 传统LZD算法和LZA算法 1. 基础算法 算法的目标是计算出加法结果序列左边连续0的数量,下文中对...

crw1111111的博客 7375

Android Audio最全面试题及参考答案(7万字长文)

在 Android 音频系统中,应用通过框架层的 API 发出音频请求,这些请求经过音频服务层的处理,传递到 HAL 层,再由 HAL 层调用音频驱动层与硬件进行交互,最终实现音频的播放、录制等功能。在 Android 音频系统中,应用通过框架层的 API 发出音频请求,这些请求经过音频服务层的处理,传递到 HAL 层,再由 HAL 层调用音频驱动层与硬件进行交互,最终实现音频的播放、录制等功能。音频播放完成事件:当使用 MediaPlayer 等音频播放类播放音频时,音频播放完成后会触发这个事件。

大模型大数据攻城狮的专栏 2604

线程池-创建线程

线程池中的线程数除了初始阶段需要从 0 开始增加外,之后的线程数量就是固定的,就算任务数超过线程数,线程池也不会再创建更多的线程来处理任务,而是会把超出线程处理能力的任务放到任务队列中进行等待。而且就算任务队列满了,到了本该继续增加线程数的时候,由于它的最大线程数和核心线程数是一样的,所以也无法再增加新的线程了由于传进去的LinkedBlockingQueue是没有容量上限的,所以当请求数越来越多,并且无法及时处理完毕的时候,也就是请求堆积的时候,会容易造成占用大量的内存,可能会导致OOM。

存在,即合理 1431

基于PINN求解裂纹扩展问题的优化开发

本文提出了一种基于物理信息神经网络(PINN)的裂纹扩展问题求解方法。通过将线弹性断裂力学控制方程和裂纹尖端场特性嵌入神经网络损失函数,PINN有效克服了传统有限元法在处理裂纹扩展时面临的网格重构困难、计算成本高等问题。文章详细介绍了PINN网络架构设计、裂纹尖端奇异场处理、损失函数构造以及优化策略等关键技术。数值实验表明,该方法能准确预测裂纹扩展路径和应力强度因子,且在处理复杂几何和动态扩展问题时展现出显著优势。相比传统方法,PINN具有无网格、并行计算友好等特点,为断裂力学问题提供了新的求解范式。

huanghm88的专栏 152

Executors和ThreadPoolExecutor那种方式创建线程池更好

Executors和ThreadPoolExecutor那种方式创建线程池更好问题来源意外发现使用ThreadPoolExecutor 创建线程池池 问题来源 在一次使用阿里代码规约扫描历史项目时发现错误提示,提示内容如下图所示,我摘抄出部分关键信息供大家阅读。 线程池不应使用Executors去创建,而是通过ThreadPoolExecutor的方式。这样的处理方式让写的同学更加明确线程池的运行...

凌飞安 1475

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

ThreadPoolExecutor手动创建线程池优于Executors类

阿里巴巴Java开发手册》阿里作为国内Java使用最多的大厂,他出版了一部《阿里巴巴Java开发手册》,不知道大家看过没,没有看过的话,建议大家看看。对于我们编程养成良好的习惯还是很有帮助的,最近我在看到并发这一规约的时候,他们就明确了一点:线程池不允许使用 Executors来创建。在多线程编程中,线程池是一种重要的资源管理工具,用于提高程序效率和降低资源消耗。Java通过java.util.concurrent包提供了丰富的线程池管理工具,其中Executors类是创建线程池的常用工具。

weixin_43702295的博客 1099

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式

1. 通过Executors创建线程池的弊端 在创建线程池的时候,大部分人还是会选择使用Executors去创建。 下面是创建定长线程池(FixedThreadPool)的一个例子,严格来说,当使用如下代码创建线程池时,是不符合编程规范的。 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); 原因在于:(摘自阿里编码规约) 线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor.

红袖添香的博客 2340

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

为什么禁用Executors创建线程池,而用ThreadPoolExecutor创建?

阿里的 Java开发手册建议线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 禁用原因:Executors创建出来的线程池使用的全都是无界队列,而使用无界队列就可以无限保存任务,因此很有可能造成OOM异常。同时在某些类型的线程池里面,使用无界队列还会导致maxinumPoo...

XSemperFI的博客 754

使用Executors类创建线程池的弊端以及与使用ThreadPoolExecutor类的区别

介绍: 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。 为什么要使用线程池? 这里借用《Java并发编程的艺术》提到的来说一下使用线程池的好处: 降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 提高响应速度。 当任务到达时,任务可以不需要的等到线程创建就能立即执行。 提高线程的可管理性。 线程是稀缺资源,如...

SmallCarrot的博客 4519

手把手教小白创建线程池,并讲解ThreadPoolExecutor和Executors

前言 无论工作还是面试,都会接触到多线程,使用线程池的场景,笔者也是近期出去面试才了解到这个知识点的重要性。对于应届生和实习生的要求主要还是知道创建线程的方式,怎么创建线程池及怎么使用,除此之外你去面试人家都会问你原理的,所以本文就简单让大家了解线程池的创建,使用包括一些常见方法原理及参数介绍,适合三年内的同学观看。 正文 就目前啊,创建线程基本上已经不用继承Thread了,缺点:    ...

晏霖/胖虎的博客 1万+

为什么我们不用Executors默认创建线程池的方法,而直接自己手动去调用ThreadPoolExecutor去创建线程池?

引用阿里巴巴Java开发手册上的一句话 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors 返回的线程池对象的弊端如下: 1)FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 2)CachedThreadPool和 Schedu

SayBlog 2284

Java线程池创建方式完全指南:从Executors到ThreadPoolExecutor的全面剖析

本文将系统讲解Java中创建线程池的多种方式,从Executors工具类提供的5种便捷工厂方法,到生产环境必备的ThreadPoolExecutor手动创建,以及JDK 21引入的虚拟线程池,用流程图和代码示例帮你掌握各种创建方式的适用场景与风险。核心线程数=最大线程数=1,使用无界LinkedBlockingQueue。:创建一个固定大小的线程池,核心线程数=最大线程数,使用。包提供的线程池工厂类,提供了5种创建线程池的便捷方法。,是轻量级线程的Java实现,适合。:核心线程数为0,最大线程数为。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 369

为什么阿里不允许用Executors创建线程池,而是通过ThreadPoolExecutor的方式?

点击上方“码农突围”,马上关注 这里是码农充电第一站,回复“666”,获取一份专属大礼包 真爱,请设置“星标”或点个“在看” 作者:雪山上的蒲公英cnblogs.com/zjfjava/...

欢迎关注公众号:【码农突围】,回复9999,可以获取一份LeetCode刷题笔记 227

Java 多线程池ThreadPoolExecutor解析及Executors类中提供的静态方法来创建线程池

使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。 一.Java中的ThreadPoolExecutor类 四个构造方法: public class ThreadPoolExecutor exten

qq_24892029的博客 2369
上一篇: 数据库事务的特性与事务隔离级别
下一篇: 多线程之线程安全关键字synchronized
tony_code_2017
博客等级 码龄9年 34粉丝 58原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值