Java线程池

    xiaoxiao2021-12-02  23

    java线程池,作用,使用方法

    作用,真实场景

    在Android开发中,例如多个网络图片的加载,在不同线程中执行URL获取资源,创建Drawable对象,最后将图片在UI线程中显示在ImageView控件上(handler.post)。如果是不断创建新的线程,消耗过多内存。故利用线程池,复用线程,根据实际情况配置合理的线程池大小。服务器应用,当多台机器访问服务器获取数据,假设这个任务是短暂的,线程的创建和销毁非常频繁,那么就应该创建线程。

    使用方法,基本类:Executor 、ExecutorService、AbstractExecutorService、ThreadPoolExecutor、Executors

    前四个类或接口是继承关系,核心的类是ThreadPoolExecutor,该类实现了executor方法。

    Executors是工厂类,负责构建几种基本的线程池类。

    这几种基本的线程池类的构建方法:(1)newFixedThreadPool(2)newSingleThreadExecutor(3)newCachedThreadPool

    为线程池添加任务的方法:execute,submit(该方法最终也是调用execute,返回Future对象)

    线程池控制的一些方法:invokeAll,invokeAny,shutdown,shutdownNow

    实例1:

    public static void main(String[] args) { // TODO Auto-generated method stub ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(10); for(int i=0;i<15;i++){ MyTask myTask = new MyTask(i); executor.execute(myTask); System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+ executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount()); } executor.shutdown(); } static class MyTask implements Runnable { private int taskNum; public MyTask(int num) { this.taskNum = num; } @Override public void run() { System.out.println("正在执行task "+taskNum); try { Thread.currentThread().sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task "+taskNum+"执行完毕"); }

    其中Executors.newFixedThreadPool(10);是一种线程池的配置,由工厂产生,线程池的核心数和最大数都是10,

    默认的阻塞队列是LinkedBlockingQueue<Runnable>。

    在这种配置下有以下种状态情况:

    新建线程池,线程池还没来任务,则线程池中线程为0。来了任务,线程池中新建线程,线程数小于corePoolSize核心线程数,则再来任务,就新建线程来执行。线程数达到corePoolSize,由于newFixedThreadPool的设置corePoolSize=maximumPoolSize,则将线程放在阻塞队列中。当线程池中的有空闲了,就去阻塞队列中取任务执行。当线程数介于corePoolSize和maximumPoolSize时,多余的线程出现空闲,且空闲时间大于KeepAliveTime,该线程会被终止。

    现在直接使用ThreadPoolExecutor设置线程池:例如,new ThreadPoolExecutor(5, 10, 200, TimeUnit.SECONDS, new ArrayBlockingQueue(5));

    这种配置下

    状态3将改变:当线程数达到corePoolSize,任务还是会进入到阻塞队列,如果阻塞队列满了(这里设置大小5),则继续添加线程。

    当线程数达到maximumPoolSize,说明线程池达到最高负载,再有任务来就会出现异常,可以自定义拒绝RejectedExecutionHandler方法来处理

    一般情况下,任务的执行是调用execute(Runnable)没有返回值,也可以用submit(callable),返回Future对象或者Future List。

    有返回值,实例2:

    public static void main(String[] args) { // TODO Auto-generated method stub ThreadPoolExecutor executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(10); List<Myfindtask> mlist=new ArrayList<Myfindtask>(); File filedir = new File("D:/"); for(File f:filedir.listFiles()){ if(f.isDirectory()){ System.out.println(f.getPath()); Myfindtask mf=new Myfindtask("12345.txt",f.getPath()); mlist.add(mf); } } try { String s=executor.invokeAny(mlist); System.out.println(" 线程池中的线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+ executor.getQueue().size()+",已执行完的别的任务的数目:"+executor.getCompletedTaskCount()); if(s==null) System.out.println("没有找到文件位置:"); else System.out.println("找到文件位置:"+s); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } static class Myfindtask implements Callable<String>{ public Myfindtask(String filename,String path){ mfilename=filename; mpath=path; } @Override public String call() throws Exception { // TODO Auto-generated method stub String s=findfile(mpath); if(s!=null) return s; else throw new Exception("没找到"); } public String mfilename; public String mpath; public String findfile(String path){ File root = new File(path); File[] files = root.listFiles(); for(File f:files){ try { Thread.currentThread().sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } if(f.getName().equals(mfilename.toString()))return f.getPath(); } return null; } }

    创建任务类MyfindTask继承Callable,实现call方法。 该任务是在目录下查找文件,添加slelep当做耗时操作。如果找到返回路径,如果没找到,在call()方法中抛出异常,该异常会被捕获,证明是未完成任务,如果任何一个线程返回了正确值,则finally关闭所有线程。 Hook 方法: 在ThreadPoolExecutor方法中创建了两个空方法:beforeExecute(),afterExecute(),在自定义的线程池中可以对任务的执行的前后进行HOOK,做收集数据,添加LOG的处理。

    源码例子:

    一个具有暂停,恢复的线程池。源码注释里提供的一个继承ThreadPoolExecutor的类,实现了Hook方法。 class PausableThreadPoolExecutor extends ThreadPoolExecutor { private boolean isPaused; private ReentrantLock pauseLock = new ReentrantLock(); private Condition unpaused = pauseLock.newCondition(); public PausableThreadPoolExecutor(...) { super(...); } protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); pauseLock.lock(); try { while (isPaused) unpaused.await(); } catch (InterruptedException ie) { t.interrupt(); } finally { pauseLock.unlock(); } } public void pause() { pauseLock.lock(); try { isPaused = true; } finally { pauseLock.unlock(); } } public void resume() { pauseLock.lock(); try { isPaused = false; unpaused.signalAll(); } finally { pauseLock.unlock(); } } }}

    转载请注明原文地址: https://ju.6miu.com/read-679610.html

    最新回复(0)