各位老铁们,大家好,今天由我来为大家分享多线程排序应用程序,以及实现多线程的方法的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!
语c中戒断反应是什么
戒断反应即化学反应,是指分子破裂成原子,原子重新排列组合生成新分子的过程。
在反应中常伴有发光、发热、变色、生成沉淀物等,判断一个反应是否为化学反应的依据是反应是否生成新的分子。
电脑上有哪些厉害的程序软件
分享10款电脑牛逼的黑科技神器,10款都是黑科技十足。(PS:文中10款电脑软件可以直接私信我"工具7"获取)
1:office一键安装激活工具office一键安装激活工具是一款一键安装和激活office的实用软件。
它支持一键安装office2013,2016和2019,你可以任意选择office所有产品进行安装,包括主流的:Word,Excel,PPT等等;它还提供一键激活功能。
2:百度云盘搜索百度云搜索是一款功能强大的百度云文件搜索软件。
它的不需要安装,直接打开就可以使用,并且支持按照文件类型进行搜索,包括:文件夹,软件,视频,音频,电子书等等文件类型。它的搜索功能十分强大,并且直接提供文件链接。
3:MusicToolsMusicTools是一款不仅支持下载全网音乐,而且支持下载无损音乐的电脑软件。
它提供QQ音乐,网易云音乐,酷狗音乐,虾米音乐,百度音乐,千千音乐,6个主流搜索引擎;支持下载无损品质的音乐。
4:AdwCleanerAdwCleaner是一款非常好用的电脑去广告工具,并且拥有很多黑科技实用功能。
它支持解决主流浏览器主页劫持问题,支持清除莫名其妙跳出来的广告和弹窗,支持清除系统里的广告软件和有害程序,支持清除各种不需要的、不知何时被安装的奇怪软件。总之,一款黑科技十足的电脑软件。
5:天若OCR文字识别天若OCR文字识别是一款识别率很高的电脑文字识别软件。
它不仅拥有强大的文字识别功能,它还支持对复制的文字处理功能,包括:对识别出来的文字翻译,朗读,各种格式的处理。
6:CCleanerCCleaner是一款国外的功能强大的系统优化软件。
它支持清除所有的垃圾文件,支持清理临时文件夹、历史记录、回收站等垃圾信息,支持扫描清理注册表垃圾,支持磁盘分析,重复文件查找,系统还原,等等实用功能。
7:爱奇艺视频格式转MP4上次分享了腾讯视频格式转换为MP4,这次分享爱奇艺视频格式转MP4,使用方法同样简单,直接导入视频文件就可以处理了,相信这款软件对于大家也是很实用。
8:InpaintInpaint是一款去除图片水印的电脑软件,十分实用。
它的使用方法也是很简单,首先导入你要处理的带有水印的图片,然后涂抹你要去除的水印,最后点击处理图像就可以了;这款软件的去除图片水印效果也是十分给力。
9:TrafficMonitorTrafficMonitor是一款用于Windows平台的网速监控悬浮窗软件,一款用于显示当前网速、CPU及内存利用率的桌面悬浮窗小工具。
它还支持更换皮肤和自定义皮肤,支持历史流量统计,支持嵌入到任务栏显示等等功能。
10:oCam录屏oCam是一款傻瓜式录屏软件,不仅安装简单,而且使用方法简单有效。
它支持游戏录制,音频录制,屏幕录制,还可以自定义快捷键,水印,录制区域,它体积十分小巧,一款质量很高的电脑录屏软件。
Python多进程和多线程是鸡肋嘛
GIL的存在一直是富有争议的,它导致Python程序无法真正利用现代操作系统的多进程特性。需要注意的是,对于I/O图形处理、NumPy数学计算这样的耗时操作都发生在GIL之外,实际上基本不受影响,真正受影响的都是Python字节码的执行,GIL会导致性能瓶颈的出现。总之,只有在使用纯Python做CPU密集的多线程运算时GIL会是问题。GIL是什么Python的代码执行由Python虚拟机(也叫解释器主循环,CPython版本)来控制,Python在设计之初就考虑到在解释器的主循环中,同时只有一个线程在运行。即每个CPU在任意时刻只有一个线程在解释器中运行。对Python虚拟机访问的控制由全局解释锁GIL控制,正是这个锁来控制同一时刻只有一个线程能够运行。——在单核CPU下的多线程其实都只是并发,不是并行。
并发与并行区别
并发:两个或多个事件在同一时间间隔发生,或者说交替做不同事件的能力,或者说不同的代码块交替执行。并行:两个或者多个事件在同一时刻发生,或者说同时做不同事件的能力,或者说不同的代码块同时执行。并发和并行的意义
并发和并行都可以处理“多任务”,二者的主要区别在于是否是“同时进行”多个的任务。但是涉及到任务分解(有先后依赖耦合度高的任务无法做到并行)、任务运行(可能要考虑互斥、锁、共享等)、结果合并。
Python下的多线程在Python多线程下,每个线程的执行方式,如下:
获取GIL切换到这个线程去执行运行代码,这里有两种机制:指定数量的字节码指令(100个)固定时间15ms线程主动让出控制把线程设置为睡眠状态释放GIL再次重复以上步骤在Python2中,在解释器解释执行任何Python代码时,都需要先获得这把锁才行(同一时间只会有一个获得了GIL的线程在跑,其它的线程都处于等待状态等着GIL的释放),在遇到I/O操作时会释放这把锁。如果是纯计算的程序,没有I/O操作,解释器会每隔100次操作就释放这把锁,让别的线程有机会执行(这个次数可以通过sys.setcheckinterval来调整)也正是这种设定,是的多线程的CPU密集型计算非常鸡肋,下面会讲到为何如此。
而在python3中,GIL不使用ticks计数(100次,释放GIL),改为使用计时器(执行时间达到15ms阈值后,当前线程释放GIL),使得执行计算的次数更多,释放次数减少,这样对CPU密集型程序更加友好,但依然没有解决GIL导致的同一时间只能执行一个线程的问题,所以效率依然不尽如人意。
那么是不是Python的多线程是鸡肋嘛?CPU密集型(各种循环处理、计数等等),在这种情况下,ticks计数很快就会达到阈值,然后触发GIL的释放与再竞争(多个线程来回切换是需要消耗资源的),所以python下的多线程对CPU密集型代码并不友好,会触发相当频繁的线程切换。
IO密集型(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率,一个线程获得GIL发送消息,然后等待返回消息(阻塞),Python此时释放GIL,其他线程得到GIL发送消息,然后同样等待返回消息(阻塞)......,这样保证了IO传输过程时间的合理利用,减少了IO等待造成的资源浪费,提高IO传输效率)。所以python的多线程对IO密集型代码比较友好。
有哪些结论?I/O密集型使用多线程并发执行提高效率、计算密集型使用多进程(multiprocessing)并行执行提高效率。通常程序既包含IO操作又包含计算操作,那么这种情况下,在开始并发任务之前,可以先进行测试,测试多线程、多进程哪个效率高就是用哪种方式。
请注意:多核多线程比单核多线程更差,多核多进程下,CPU1释放GIL后,其他CPU上的线程都会进行竞争,但GIL可能会马上又被CPU1拿到,CPU2释放GIL后……,导致其他几个CPU上被唤醒后的线程会醒着等待到切换时间后又进入待调度状态,这样会造成线程颠簸(thrashing),导致效率更低。
多线程下的CPU密集型计算也不是无药可医,可以利用ctypes绕过GIL,ctypes可以使py直接调用任意的C动态库的导出函数。所要做的只是把关键部分用C/C++写成Python扩展。而且,ctypes会在调用C函数前释放GIL。
同时,可以了解下协程,又称微线程。
协程最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
如何优雅的使用和理解线程池你怎么看
提示
请带着这些问题继续后文,会很大程度上帮助你更好的理解相关知识点。@pdai
为什么要有线程池?Java是实现和管理线程池有哪些方式?请简单举例如何使用。为什么很多公司不允许使用Executors去创建线程池?那么推荐怎么使用呢?ThreadPoolExecutor有哪些核心的配置参数?请简要说明ThreadPoolExecutor可以创建哪是哪三种线程池呢?当队列满了并且worker的数量达到maxSize的时候,会怎么样?说说ThreadPoolExecutor有哪些RejectedExecutionHandler策略?默认是什么策略?简要说下线程池的任务执行机制?execute–>addWorker–>runworker(getTask)线程池中任务是如何提交的?线程池中任务是如何关闭的?在配置线程池的时候需要考虑哪些配置因素?如何监控线程池的状态?为什么要有线程池线程池能够对线程进行统一分配,调优和监控:
降低资源消耗(线程无限制地创建,然后使用完毕后销毁)提高响应速度(无须创建线程)提高线程的可管理性ThreadPoolExecutor例子Java是如何实现和管理线程池的?
从JDK5开始,把工作单元与执行机制分离开来,工作单元包括Runnable和Callable,而执行机制由Executor框架提供。
WorkerThreadSimpleThreadPool
程序中我们创建了固定大小为五个工作线程的线程池。然后分配给线程池十个工作,因为线程池大小为五,它将启动五个工作线程先处理五个工作,其他的工作则处于等待状态,一旦有工作完成,空闲下来工作线程就会捡取等待队列里的其他工作进行执行。
这里是以上程序的输出。
输出表明线程池中至始至终只有五个名为"pool-1-thread-1"到"pool-1-thread-5"的五个线程,这五个线程不随着工作的完成而消亡,会一直存在,并负责执行分配给线程池的任务,直到线程池消亡。
Executors类提供了使用了ThreadPoolExecutor的简单的ExecutorService实现,但是ThreadPoolExecutor提供的功能远不止于此。我们可以在创建ThreadPoolExecutor实例时指定活动线程的数量,我们也可以限制线程池的大小并且创建我们自己的RejectedExecutionHandler实现来处理不能适应工作队列的工作。
这里是我们自定义的RejectedExecutionHandler接口的实现。
RejectedExecutionHandlerImpl.javaThreadPoolExecutor提供了一些方法,我们可以使用这些方法来查询executor的当前状态,线程池大小,活动线程数量以及任务数量。因此我是用来一个监控线程在特定的时间间隔内打印executor信息。
MyMonitorThread.java这里是使用ThreadPoolExecutor的线程池实现例子。
WorkerPool.java注意在初始化ThreadPoolExecutor时,我们保持初始池大小为2,最大池大小为4而工作队列大小为2。因此如果已经有四个正在执行的任务而此时分配来更多任务的话,工作队列将仅仅保留他们(新任务)中的两个,其他的将会被RejectedExecutionHandlerImpl处理。
上面程序的输出可以证实以上观点。
注意executor的活动任务、完成任务以及所有完成任务,这些数量上的变化。我们可以调用shutdown()方法来结束所有提交的任务并终止线程池。
ThreadPoolExecutor使用详解其实java线程池的实现原理很简单,说白了就是一个线程集合workerSet和一个阻塞队列workQueue。当用户向线程池提交一个任务(也就是线程)时,线程池会先将任务放入workQueue中。workerSet中的线程会不断的从workQueue中获取线程然后执行。当workQueue中没有任务的时候,worker就会阻塞,直到队列中有任务了就取出来继续执行。
Execute原理当一个任务提交至线程池之后:
线程池首先当前运行的线程数量是否少于corePoolSize。如果是,则创建一个新的工作线程来执行任务。如果都在执行任务,则进入2.判断BlockingQueue是否已经满了,倘若还没有满,则将线程放入BlockingQueue。否则进入3.如果创建一个新的工作线程将使当前运行的线程数量超过maximumPoolSize,则交给RejectedExecutionHandler来处理任务。当ThreadPoolExecutor创建新线程时,通过CAS来更新线程池的状态ctl.
参数corePoolSize线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize,即使有其他空闲线程能够执行新来的任务,也会继续创建线程;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。workQueue用来保存等待被执行的任务的阻塞队列.在JDK中提供了如下阻塞队列:具体可以参考JUC集合:BlockQueue详解ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;LinkedBlockingQueue:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQueue;SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue;PriorityBlockingQueue:具有优先级的无界阻塞队列;LinkedBlockingQueue比ArrayBlockingQueue在插入删除节点性能方面更优,但是二者在put(),take()任务的时均需要加锁,SynchronousQueue使用无锁算法,根据节点的状态判断执行,而不需要用到锁,其核心是Transfer.transfer().
maximumPoolSize线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于maximumPoolSize;当阻塞队列是无界队列,则maximumPoolSize则不起作用,因为无法提交至核心线程池的线程会一直持续地放入workQueue.keepAliveTime线程空闲时的存活时间,即当线程没有任务执行时,该线程继续存活的时间;默认情况下,该参数只在线程数大于corePoolSize时才有用,超过这个时间的空闲线程将被终止;unitkeepAliveTime的单位threadFactory创建线程的工厂,通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名。默认为DefaultThreadFactoryhandler线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:AbortPolicy:直接抛出异常,默认策略;CallerRunsPolicy:用调用者所在的线程来执行任务;DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;DiscardPolicy:直接丢弃任务;当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。
三种类型newFixedThreadPool线程池的线程数量达corePoolSize后,即使线程池没有可执行任务时,也不会释放线程。
FixedThreadPool的工作队列为无界队列LinkedBlockingQueue(队列容量为Integer.MAX_VALUE),这会导致以下问题:
线程池里的线程数量不超过corePoolSize,这导致了maximumPoolSize和keepAliveTime将会是个无用参数由于使用了无界队列,所以FixedThreadPool永远不会拒绝,即饱和策略失效newSingleThreadExecutor初始化的线程池中只有一个线程,如果该线程异常结束,会重新创建一个新的线程继续执行任务,唯一的线程可以保证所提交任务的顺序执行.
由于使用了无界队列,所以SingleThreadPool永远不会拒绝,即饱和策略失效
newCachedThreadPool线程池的线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue作为阻塞队列;和newFixedThreadPool创建的线程池不同,newCachedThreadPool在没有任务执行时,当线程的空闲时间超过keepAliveTime,会自动释放线程资源,当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销;执行过程与前两种稍微不同:
主线程调用SynchronousQueue的offer()方法放入task,倘若此时线程池中有空闲的线程尝试读取SynchronousQueue的task,即调用了SynchronousQueue的poll(),那么主线程将该task交给空闲线程.否则执行(2)当线程池为空或者没有空闲的线程,则创建新的线程执行任务.执行完任务的线程倘若在60s内仍空闲,则会被终止.因此长时间空闲的CachedThreadPool不会持有任何线程资源.关闭线程池遍历线程池中的所有线程,然后逐个调用线程的interrupt方法来中断线程.
关闭方式-shutdown将线程池里的线程状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程.
关闭方式-shutdownNow将线程池里的线程状态设置成STOP状态,然后停止所有正在执行或暂停任务的线程.只要调用这两个关闭方法中的任意一个,isShutDown()返回true.当所有任务都成功关闭了,isTerminated()返回true.
ThreadPoolExecutor源码详解几个关键属性内部状态其中AtomicInteger变量ctl的功能非常强大:利用低29位表示线程池中线程数,通过高3位表示线程池的运行状态:
RUNNING:-1<<COUNT_BITS,即高3位为111,该状态的线程池会接收新任务,并处理阻塞队列中的任务;SHUTDOWN:0<<COUNT_BITS,即高3位为000,该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;STOP:1<<COUNT_BITS,即高3位为001,该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,而且会中断正在运行的任务;TIDYING:2<<COUNT_BITS,即高3位为010,所有的任务都已经终止;TERMINATED:3<<COUNT_BITS,即高3位为011,terminated()方法已经执行完成任务的执行execute–>addWorker–>runworker(getTask)
线程池的工作线程通过Woker类实现,在ReentrantLock锁的保证下,把Woker实例插入到HashSet后,并启动Woker中的线程。从Woker类的构造方法实现可以发现:线程工厂在创建线程thread时,将Woker实例本身this作为参数传入,当执行start方法启动线程thread时,本质是执行了Worker的runWorker方法。firstTask执行完成之后,通过getTask方法从阻塞队列中获取等待的任务,如果队列中没有任务,getTask方法会被阻塞并挂起,不会占用cpu资源;
execute()方法ThreadPoolExecutor.execute(task)实现了Executor.execute(task)
为什么需要doublecheck线程池的状态?在多线程环境下,线程池的状态时刻在变化,而ctl.get()是非原子操作,很有可能刚获取了线程池状态后线程池状态就改变了。判断是否将command加入workque是线程池之前的状态。倘若没有doublecheck,万一线程池处于非running状态(在多线程环境下很有可能发生),那么command永远不会执行。
addWorker方法从方法execute的实现可以看出:addWorker主要负责创建新的线程并执行任务线程池创建新线程执行任务时,需要获取全局锁:
Worker类的runworker方法继承了AQS类,可以方便的实现工作线程的中止操作;实现了Runnable接口,可以将自身作为一个任务在工作线程中执行;当前提交的任务firstTask作为参数传入Worker的构造方法;一些属性还有构造方法:
runWorker方法是线程池的核心:
线程启动之后,通过unlock方法释放锁,设置AQS的state为0,表示运行可中断;Worker执行firstTask或从workQueue中获取任务:进行加锁操作,保证thread不被其他线程中断(除非线程池被中断)检查线程池状态,倘若线程池处于中断状态,当前线程将中断。执行beforeExecute执行任务的run方法执行afterExecute方法解锁操作通过getTask方法从阻塞队列中获取等待的任务,如果队列中没有任务,getTask方法会被阻塞并挂起,不会占用cpu资源;
getTask方法
下面来看一下getTask()方法,这里面涉及到keepAliveTime的使用,从这个方法我们可以看出线程池是怎么让超过corePoolSize的那部分worker销毁的。
注意这里一段代码是keepAliveTime起作用的关键:
allowCoreThreadTimeOut为false,线程即使空闲也不会被销毁;倘若为ture,在keepAliveTime内仍空闲则会被销毁。
如果线程允许空闲等待而不被销毁timed==false,workQueue.take任务:如果阻塞队列为空,当前线程会被挂起等待;当队列中有任务加入时,线程被唤醒,take方法返回任务,并执行;
如果线程不允许无休止空闲timed==true,workQueue.poll任务:如果在keepAliveTime时间内,阻塞队列还是没有任务,则返回null;
任务的提交submit任务,等待线程池execute执行FutureTask类的get方法时,会把主线程封装成WaitNode节点并保存在waiters链表中,并阻塞等待运行结果;FutureTask任务执行完成后,通过UNSAFE设置waiters相应的waitNode为null,并通过LockSupport类unpark方法唤醒主线程;在实际业务场景中,Future和Callable基本是成对出现的,Callable负责产生结果,Future负责获取结果。
Callable接口类似于Runnable,只是Runnable没有返回值。Callable任务除了返回正常结果之外,如果发生异常,该异常也会被返回,即Future可以拿到异步执行任务各种结果;Future.get方法会导致主线程阻塞,直到Callable任务执行完成;submit方法AbstractExecutorService.submit()实现了ExecutorService.submit()可以获取执行完的返回值,而ThreadPoolExecutor是AbstractExecutorService.submit()的子类,所以submit方法也是ThreadPoolExecutor`的方法。
通过submit方法提交的Callable任务会被封装成了一个FutureTask对象。通过Executor.execute方法提交FutureTask到线程池中等待被执行,最终执行的是FutureTask的run方法;
FutureTask对象publicclassFutureTask<V>implementsRunnableFuture<V>可以将FutureTask提交至线程池中等待被执行(通过FutureTask的run方法来执行)
内部状态内部状态的修改通过sun.misc.Unsafe修改
get方法内部通过awaitDone方法对主线程进行阻塞,具体实现如下:
如果主线程被中断,则抛出中断异常;
判断FutureTask当前的state,如果大于COMPLETING,说明任务已经执行完成,则直接返回;如果当前state等于COMPLETING,说明任务已经执行完,这时主线程只需通过yield方法让出cpu资源,等待state变成NORMAL;通过WaitNode类封装当前线程,并通过UNSAFE添加到waiters链表;最终通过LockSupport的park或parkNanos挂起线程;run方法
FutureTask.run方法是在线程池中被执行的,而非主线程
通过执行Callable任务的call方法;如果call执行成功,则通过set方法保存结果;如果call执行有异常,则通过setException保存异常;任务的关闭shutdown方法会将线程池的状态设置为SHUTDOWN,线程池进入这个状态后,就拒绝再接受任务,然后会将剩余的任务全部执行完
shutdownNow做的比较绝,它先将线程池状态设置为STOP,然后拒绝所有提交的任务。最后中断左右正在运行中的worker,然后清空任务队列。
更深入理解
为什么线程池不允许使用Executors去创建?推荐方式是什么?线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。说明:Executors各个方法的弊端:
newFixedThreadPool和newSingleThreadExecutor:??主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。newCachedThreadPool和newScheduledThreadPool:??主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。推荐方式1首先引入:commons-lang3包
推荐方式2首先引入:com.google.guava包
推荐方式3spring配置线程池方式:自定义线程工厂bean需要实现ThreadFactory,可参考该接口的其它默认实现类,使用方式直接注入bean调用execute(Runnabletask)方法即可
配置线程池需要考虑因素
从任务的优先级,任务的执行时间长短,任务的性质(CPU密集/IO密集),任务的依赖关系这四个角度来分析。并且近可能地使用有界的工作队列。
性质不同的任务可用使用不同规模的线程池分开处理:
CPU密集型:尽可能少的线程,Ncpu+1IO密集型:尽可能多的线程,Ncpu*2,比如数据库连接池混合型:CPU密集型的任务与IO密集型任务的执行时间差别较小,拆分为两个线程池;否则没有必要拆分。监控线程池的状态可以使用ThreadPoolExecutor以下方法:
getTaskCount()Returnstheapproximatetotalnumberoftasksthathaveeverbeenscheduledforexecution.getCompletedTaskCount()Returnstheapproximatetotalnumberoftasksthathavecompletedexecution.返回结果少于getTaskCount()。getLargestPoolSize()Returnsthelargestnumberofthreadsthathaveeversimultaneouslybeeninthepool.返回结果小于等于maximumPoolSizegetPoolSize()Returnsthecurrentnumberofthreadsinthepool.getActiveCount()Returnstheapproximatenumberofthreadsthatareactivelyexecutingtasks.参考文章《Java并发编程艺术》https://www.jianshu.com/p/87bff5cc8d8chttps://blog.csdn.net/programmer_at/article/details/79799267https://blog.csdn.net/u013332124/article/details/79587436https://www.journaldev.com/1069/threadpoolexecutor-java-thread-pool-example-executorservice由于问答代码块插入受限,部分代码未完全展示,若有需要可阅读原文:戳我阅读原文
可以推荐一些好用的手机应用吗
非常高兴为你解答这个问题
这个问题我最有回答权力了,作为一个手机APP重度患者,我每天都在逛应用商店或各大网站来找各样有趣的APP,我手机里也有好多有趣对身心有益的APP。
今天先在这推荐三个吧
第一个:图凌这个APP是款壁纸APP,但它不光是一款壁纸APP还是一个优质的图片分享平台,里面有很多用户分享的原图,并且大部分画质已经达到了4k,非常非常清晰。对像我这样一张壁纸3天就看腻的人实在太友好了。
我最喜欢的就是它的启动页,真的很好看,在我知道的APP里简直就是一股清流。
这款APP最大的缺点就是它有限制下载次数,并且有会员制度,拥有会员之后每天也只能下载500张。
第二个:小日常-习惯打卡这个APP从名字应该就能猜出来是一款打卡APP。
这款APP可以设置很多打卡习惯,并且可以自定义设置习惯,进行打卡。对我这样有拖延症和忘性大的人非常有帮助,是个养成习惯的好应用。
它的应用页面也十分具有卡通风格,非常好看,我每次看都很舒心。
第三个:储存空间清理这个APP也可以从名字上看出来,是一款清理空间的APP。清洁功能十分强劲,简直是在用铲子刮手机垃圾。
我们手机里东西越来越多,垃圾也越来越多,内存不够了,手机自带的管家往往只会清理表面的东西,而这款APP拥有非常强力的清洁功能。它会检测扫描你手机里所有的东西,一键删除,也可以自己选择手动删除。
但是这个APP的缺点也很明显。那就是这个页面实在太简洁了,甚至可以说丑。
还有就是对一些人不太友好不太好用。我第一次进入之后,我是懵逼的,这个该怎么用,因为蓝色的页面实在是太容易让人分不清,不过作者也贴心的制作了应用教程,了解之后还是很好用的。
在这里就先说这三个应用吧。这些应用虽然好用,但是我们也不能过分的依赖它,像第二个打卡应用,虽然可以帮你养成习惯,但是它也只是辅助你,真正要靠的还是你自己去养成这个习惯,不能一昧去依赖这个应用,过分的依赖对我们来说不是好事。
我现在也在慢慢的不依靠这个应用来养成习惯。
好了,文章到这里就结束啦,如果本次分享的多线程排序应用程序和实现多线程的方法问题对您有所帮助,还望关注下本站哦!