对象池和线程池

实际开发中,并发和多线程的情景处处存在。今天我们来聊聊对象池和线程池这个两个日常开发用的比较多,但是又很容易混淆的两个概念。

对象池

首先我们来说说对象池。对象池利用了串行封闭的概念:将对象O“借给”一个请求线程T1,T1使用完之后再交还给对象池,并保证“未擅自发布该对象”且“以后不再使用”;对象池收回对象O之后,等T2来借的时候再把他借给T2,完成对象所用权的传递。

下面是一个简化版的对象池

public abstract class AbstractObjectPool<T> {
    protected final int min;
    protected final int max;
    protected final List<T> usings = Lists.newLinkedList();
    protected final List<T> buffer = Lists.newLinkedList();
    private volatile boolean inited = false;

    public AbstractObjectPool(int min, int max) {
        this.min = min;
        this.max = max;
        if (this.min < 0 || this.min > this.max) {
            throw new IllegalArgumentException(String.format("need 0<=min<=max<=Integer.MAX_VALUE,given min%s,max:%s", this.min, this.max));
        }
    }

    public void init() {
        for (int i = 0; i < min; i++) {
            buffer.add(newObject());
        }
        inited = true;
    }

    public void checkInited() {
        if (!inited) {
            throw new IllegalStateException("not inited");
        }
    }

    abstract protected T newObject();

    public synchronized T getObject() {
        checkInited();
        if (usings.size() == max) {
            return null;
        }
        if (buffer.size() == 0) {
            T newObject = newObject();
            usings.add(newObject);
            return newObject;
        }

        T oldObject = buffer.remove(0);
        usings.add(oldObject);
        return oldObject;
    }

    public synchronized void freeObject(T object) {
        checkInited();
        if (!usings.contains(object)) {
            throw new IllegalArgumentException(String.format("object not in using queue:%s", object));
        }
        usings.remove(usings.indexOf(object));
        buffer.add(object);
    }
}

AbstractObjectPool具有以下特性:

  • 支持设置最小最大容量
  • 对象一旦申请就不再释放,避免了GC

虽然简单,但是大可以用于一些时间敏感、资源充裕的场景。如果时间进一步敏感,可将getObject()、freeObject()改写为并发程度更高的版本,但是记得得保证安全发布安全回收;如果资源不那么充裕,可以适当增加对象的回收策略。

可以看到,一个对象池的基本行为包括:

  • 创建对象newObject()
  • 借取对象getObject()
  • 归还对象freeObject()

典型的对象池有各种连接池(如数据库连接池)、常量池等。那对象池和线程是之间有什么区别呢,线程池的核心原理是不是对象池,下面我们来追溯一下java源码。

线程池

首先摆出结论:线程池糅合了对象池模型,但是核心原理是生产者-消费者模型。

继承结构如下:

用户可以将Runnable(或Callables)实例提交给线程池,线城池会异步执行该任务,返回响应的结果(完成/返回值)。

我最喜欢的是submit(Callable<T> task)方法。我们从该方法入手,逐步深入函数栈,探究线程池的实现原理。

submit()

submit()方法在ExecutorService接口中定义,在抽象类AbstractExecutorService实现,ThreadPoolExecutor直接继承。

public abstract class AbstractExecutorService implements ExecutorService {

    ...

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
}

AbstractExecutorService #newTaskFor()创建一个RunnableFutrue类型的FutureTask。核心是execute()方法

execute()方法

execute()方法在接口Executor定义,在ThreadPoolExecutor实现。

public class ThreadPoolExecutor extends AbstractExecutorService {
    ...
    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);
   }
   ...
}

我们暂且忽略线程池的池化策略。关注一个最简单的场景,看看线程池中任务是怎样执行的。

核心是addWorker()方法。以第8行为例,此时,线程池中线程数未达到最小线程池的大小corePoolSize,通常可以直接在第9行返回。

addWorker()

addWorker()方法是ThreadPoolExecutor的私有方法。

public class ThreadPoolExecutor extends AbstractExecutorService {
    ....
    private boolean addWorker(Runnable firstTask, boolean core) {
        ...
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {                    
                    int rs = runStateOf(ctl.get());
                    if (rs < SHUTDOWN){                       
                        workers.add(w);                       
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
    ....
}

这里去掉了很多用于管理线程池、维护线程安全的代码。假设线程池未关闭,worker(即w,下同)添加成功,则必然将worker添加至workers中。workers是一个HashSet:

    /**
     * Set containing all worker threads in pool. Accessed only when
     * holding mainLock.
     */
    private final HashSet<Worker> workers = new HashSet<Worker>();
哪里是对象池

如果说与对象池有关,那么只有workers及相当于对象池实例代码中的using,应用了对象池模型;只不过这里的using是一直增长的,直到打到最大线程池的大小maximumPoolSize。

但是很明显,线程池并没有将线程发布出去,workers仅仅是完成using保存线程的作用。那么线程池中的任务是怎样执行的呢?跟线程池有没有关系呢?

哪里又不是对象池?

注意上面addWorker()代码中的第9、17、24行代码

  • 9行将我们提交到线程池的firstTask封装入一个worker.
  • 17行将worker加入到workers维护起来
  • 24行启动了worker中的线程t

核心就在这三行,线程池没有直接在addWorker()中启动我们传进来的firstTask,代之以启动 一个worker,最终任务必然被启动,那么我们继续看Worker是怎样启动我们这个任务的。

Worker

Worker实现了Runnable接口:

private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
    ...
    /**
     * Creates with given first task and thread from ThreadFactory.
     * @param firstTask the first task (null if none)
     */
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }

    /** Delegates main run loop to outer runWorker  */
    public void run() {
        runWorker(this);
    }
    ...
}

为什么要将构造Worker时的参数命名为firstTask?因为当且仅当需要建立新的Worker以执行任务task时,才会调用构造函数。因此,任务task对于新Worker而言,是第一个任务firstTask。

Worker的实现非常简单:将自己作为Runable实例,构造时在内部创建并持有一个线程thread。Thread和Runable的使用大家很熟悉了,核心是Worker的run方法,它直接调用了runWorker()方法。

runWorker()

重点来了。简化如下:

public class ThreadPoolExecutor extends AbstractExecutorService {
    ...
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                 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);
        }
    }
    ...
}

我们在前面将要执行的任务赋值给firstTask,5-6行首先取出任务task,并将firstTask置为null。因为接下来要执行task,firstTask字段就没有用了。

重点是10-31行的while循环。下面分情况讨论。

case1:第一次进入循环,task不为null

case1对应前面所有假设,程序正常运行进入到这个while循环。

第一次进入循环时,task==firstTask,不为null,直接进入循环体;从而执行16行的firstTask的run()方法;
异常处理我们在这里先不考虑;最后,在finally代码块中,task被置为null,导致下一轮循环会进入case2。

case2:非第一次进入循环体,task为null

case2是更为普遍的情况,是线程池的核心。

case1中,task被置为null,使得第10行的布尔表达式执行第二部分:(task = getTask()) != null) (注:getTask()方法稍后再讲,它返回一个用户已提交的任务)。假设task得到一个已提交的任务,从而16行执行的是新获得的新任务的run()方法。后面通case1,最后task也会被置为null,以后循环都进入case2。

getTask()

case2中每次循环都要获取一个新的已提交的任务,那任务从哪来呢?简化如下

public class ThreadPoolExecutor extends AbstractExecutorService {
    ...
    private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?
        for (;;) {
            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }
    ...
}

我们先看简单的7-11行。

首先,workQueue是一个线程安全的BlockingQueue,大部分时候使用的实现类是LinkedBlockingQueue。

private final BlockingQueue<Runnable> workQueue;

假设timed为 false,则调用阻塞的take()方法,返回的一定不是null,从而在11行return退出,将获取到的task交给某个worker线程去执行。

workQueue中的元素从哪来呢 ?这就要回到最初的execute()方法了。

execute()
public class ThreadPoolExecutor extends AbstractExecutorService {
    ...
    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);
   }
   ...
}

前面以8行的参数为例,此时,线程池中的线程数未达到最小线程池的大小corePoolSize,通常这个时候直接在第10行返回。

如果不满足8行的条件,则会执行到13行的。isRunning(c)判断线程池是否未关闭,这里我们只关注未关闭的情况;接下来就会执行布尔表达式的第二部分workQueue.offer(command),尝试将任务放入到队列workQueue中。

workQueue.offer()的行为取决于线程池持有的BlockingQueue实例。
Executors.newFixedThreadPool()、Executors.newSingleThreadExecutor()创建的线程池使用LinkedBlockingQueue,而Executors.newCachedThreadPool()创建的线程池则使用SynchronousQueue。

public class Executors {
    ...
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
}

以LinkedBlockingQueue为例,创建时不配置容量,即创建为无界队列,则LinkedBlockingQueue#offer()永远返回true,从而进入execute()13-19行。

当workQueue.offer()返回true时,已经将任务command放入队列workQueue中。当未来某个时刻,某worker完成一个任务后,会通过getTask()从workerQueue在获取一个任务继续执行,直到线程池关闭,直到海枯石烂。

case2小结

可以看到,实际上,线程池的核心原理与对象池模型无关,而是生产者-消费者模型。

  • 生产者(调用submit()或者execute()方法)将任务Task放入队列
  • 消费者(worker线程)循环从任务队列中取出任务处理(执行task.run())
钩子方法

回到runWorker()方法,在执行任务的过程中,线程池保留了一些钩子方法,如beforeExecute()、afterExecute()。用户可以在实现自己的线程池时,可以通过覆写钩子方法为线程池添加功能。

总结

对象池和线程池关系不大,但是经常会混淆。线程池的实现很有意思。在追溯源码之前,我一直以为线程池就是把线程存起来,用的时候取出一个执行任务;看了源码才知道它实现如此之妙,简洁优雅效率高。源码才是最好的老师。

深入理解对象池、线程池与数据库连接池 实现一个健壮的对象池需要考虑许多细节,例如同步机制、资源回收策略、池的大小限制等。下面是一个简单的自定义对象池的设计与实现:i++) {return obj;这个对象池实现了基本的借出(borrowObject)、归还(returnObject)和销毁(invalidateObject)对象的逻辑。它使用来保证线程安全,并允许对象的复用。 阅读详情

相关推荐

线程池与对象池的融合

这是一个很简单的实现啦对象池与线程池的融合,方法的主要参数,线程池大小、对象池大小、对象的创建工厂(继承接口自己实现),执行时传入方面名称即可。(invoke方法第一个为参数为方法名,第二是可变参数(及方法参数),invokeReturn为带返回值的方法)!

浅谈线程池(中):独立线程池的作用及IO线程池

在上一篇文章中,我们简单讨论了线程池的作用,以及CLR线程池的一些特性。不过关于线程池的基本概念还没有结束,这次我们再来补充一些必要的信息,有助于我们在程序中选择合适的使用方式。 独立线程池 上次我们讨论到,在一个.NET应用程序中会有一个CLR线程池,可以使用ThreadPool类中的静态方法来使用这个线程池。我们只要使用QueueUserWorkItem方法向线程池中添加任务,线程池就会负责在...

weixin_33744854的博客 360

Upwork数据战争:用爬虫与AI预测垄断订单

当普通自由职业者还在“等客户发需求”时,顶尖玩家已用数据预测客户明天需要什么; 当竞争对手熬夜抢单时,你的爬虫早已自动提交提案—— 这不是科幻,而是2025年的现实! 本文将手把手教你用合法工具搭建“数据战情室”,让每个决策都有万亿级数据支撑!

qq_61813593的博客 980

C/C++ 线程池的作用与结构 & C++代码实现

本文介绍了线程池的作用,线程池的结构示意图,并用C++实现了一个较为完整的线程池,附代码和详细的注释

98kaiii的博客 380

Kali Linux下Havoc框架编译避坑指南:从环境配置到成功运行的全流程

本文提供了在Kali Linux系统上成功编译和运行Havoc开源框架的详细指南。文章重点解析了从Go语言环境配置、系统依赖库安装到交叉编译环境搭建的全流程,并针对编译过程中常见的Qt、Boost及mingw-w64等依赖问题给出了具体的解决方案,帮助安全研究人员绕过常见陷阱,顺利完成环境部署。

weixin_29230865的博客 94

VS2019 从零构建 OSG+OSGEarth+OSGQt 开发环境实战指南

本文提供了一份详细的实战指南,指导开发者如何在Windows系统下使用VS2019从零开始编译和配置OSG、OSGEarth与OSGQt开发环境。文章涵盖了从环境准备、源码获取、CMake配置、Visual Studio编译到最终测试的完整流程,并分享了关键的避坑技巧,旨在帮助三维GIS与可视化开发者高效搭建稳定、可控的专业开发平台。

weixin_28826961的博客 366

对象池、连接池、线程池

什么是对象池,什么是线程池,什么是连接池,它们3个有什么区别。 对象池技术基本原理的核心有两点:缓存和共享,即对于那些被频繁使用的对象,在使用完后,不立即将它们释放,而是将它们缓存起来,以供后续的应用程序重复使用,从而减少创建对象和释放对象的次数,进而改善应用程序的性能。事实上,由于对象池技术将对象限制在一定的数量,也有效地减少了应用程序内存上的开销。 线程池以及连接池实现的原理也是跟对象池基

zfqzpp的专栏 2286

爬虫实战:拆解WASM加密参数,破局2026电商动态接口反爬(实测某头部电商可用)

sign和wasm_token,而且每次请求这两个参数都在动态变化。用常规的参数拼接、MD5加密尝试还原,结果全是403;反编译前端JS,发现核心加密逻辑被打包成了.wasm,把关键参数加密、签名逻辑藏在二进制模块里,让爬虫无法直接逆向JS拿到加密规则。前后折腾了5天,从WASM文件解析、JS与WASM交互逻辑拆解,到本地还原加密参数、实战验证,踩了无数坑(比如WASM版本不兼容、内存数据读取失败、加密依赖环境缺失),最终成功还原了加密流程,稳定爬取商品详情、价格、销量等核心数据,连续运行72小时无封禁。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1909

用好对象池模式,性能提升10倍!

总之,对象池模式是一种强大的设计模式,可以通过重用昂贵的对象显著提高应用程序性能和效率。它提供了一种管理共享资源的机制,并通过限制创建的对象数量来防止资源耗尽。如果使用得当,对象池模式可以成为提高软件应用程序的可伸缩性和可靠性的有效工具。

m0_71777195的博客 483

从零到精通:BLDC电机驱动电路详解与设计思路

这套电机驱动电路从核心控制器到反馈采集模块,涉及了BLDC电机驱动的方方面面。每一个模块的设计和选择都需要综合考虑系统需求和实际使用环境。在实际应用中,很多细微的设计改进都会显著影响电机的运行性能。

weixin_43199439的博客 3099

【PCL点云配准】位姿估计

本文介绍了PCL(Point Cloud Library)中TransformationEstimation模块的核心算法原理和实现方法。该模块通过多种子类(如SVD、LM、双四元数等)提供点云配准功能,支持2D/3D刚性变换估计。主要内容包括:1)各类变换估计算法的数学原理和实现细节;2)点对点/点对面两种误差度量方法;3)线性闭式解和非线性迭代两种求解方式;4)变换验证机制;5)基于三点法的完整代码示例。该模块广泛应用于SLAM、三维重建等领域,为点云配准提供了高效可靠的解决方案。

yijiujiusan的博客 240

对象池、连接池、线程池等池化技术,你真的会用吗?

池化技术是一种资源管理策略,通过预先创建和维护一组可重用的对象或者连接,减少频繁创建和销毁这些资源的开销,常见的就有对象池、数据库连接池、Http连接池、线程池等等, 分别对应一些常用的Java库: commons-pool、commons-dbcp、Apache-httpclient、TreadPool等等。- 配置复杂性: 需要合理配置池的大小、逐出策略等参数- 资源泄漏:如果对象或连接没有正确归还到池中,可能会导致资源泄漏。

猿起缘灭丶的博客 1044

Python爬虫实战:使用最新技术爬取GitHub Trending项目

本文将详细介绍如何使用Python最新技术栈构建一个高效的GitHub Trending爬虫。我们将使用异步请求库httpx、HTML解析库parsel、数据存储方案以及反反爬技术,完整实现一个能够稳定获取GitHub Trending数据的爬虫系统。文章包含5000余字详细教程,从环境搭建到代码实现,再到数据处理和存储,最后部署运行,提供全方位指导。GitHub Trending页面展示了GitHub上当前最受欢迎的项目,对于开发者了解技术趋势、发现优秀项目非常有价值。

2201_76125261的博客 735

Servlet 线程池 和 EJB 对象池

Servlet 线程池 和 EJB 对象池 2008/11/13 07:26 P.M. 转至http://hi.baidu.com/%D3%C0%CA%C0%CF%E9%BA%CD/blog/item/ca83e8876c55142dc65cc31a.html 目前所有的B/S系统应用可以分为:有状态(statefull)和无状态(stateless)两大类别。有状态是指在整个系统的处理过程中...

weixin_30512785的博客 106

企业级大数据平台的数据网格(Data Mesh)转型之路

随着企业数字化转型的深入,传统大数据平台面临数据孤岛化、治理成本高、业务响应慢等核心痛点。数据网格作为一种新兴的分布式数据管理架构,通过领域驱动设计(DDD)、数据产品化和联邦治理模式,为企业提供了打破数据壁垒、提升数据生产力的全新路径。本文聚焦企业级数据平台从传统架构(数据湖/数据仓库)向数据网格转型的关键技术、实施步骤和组织配套,涵盖技术架构设计、核心算法实现、项目实战案例及工具链推荐。背景介绍:定义转型目标、术语体系与核心挑战核心概念与联系:解析数据网格四大支柱及技术架构图谱核心算法原理。

AI 领航者的博客 1083

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Java 数据库连接池、线程池和对象池总结

Java线程池总结 Java线程池总结

langjian2012的专栏 4301

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

内存池、线程池和对象池

内存池 C/C++下内存管理是让几乎每一个程序员头疼的问题,分配足够的内存、追踪内存的分配、在不需要的时候释放内存——这个任务相当复杂。而直接使用系统调用malloc/free、new/delete进行内存分配和释放,有以下弊端: 调用malloc/new,系统需要根据“最先

470

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

源码|从串行线程封闭到对象池、线程池

相对于线程封闭,串行线程封闭离用户的距离更近一些,简单灵活,实用性强,很容易掌握。而线程封闭更多沦为单纯的设计策略,单纯使用线程封闭的场景不多。线程池与串行线程封闭、对象池的关系不大,但经常被混为一谈;没看过源码的很难想到其实现方案,面试时也能立分高下。线程池的实现很有意思。在追源码之前,猴子一直以为线程池就是把线程存起来,用的时候取出来执行任务;看了源码才知道实现如此之妙,简洁优雅效率高。源码才是最好的老师。原文地址:源码|从串行线程封闭到对象池、线程池。

攻城狮不是猫 984

专业词汇之对象池、连接池、线程池

在绝大多数的JavaWeb的应用系统开发过程中,经常会听到或见到这样的三个专业名词:对象池、连接池、线程池。下面就这三个专业知识做一个简单的小结:        1.对象池        对象池技术通常是在服务器端开发使用的技术,使用该项技术的主要原因是减少从头创建每个对象的系统开销,提高系统性能。其主要做法是:创建一个对象池,将一定数量的对象缓存到这个对象池中,需要使用时直接从对象池

zh_winer的博客 1535

线程池的基本思想还是一种对象池的思想

线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。比如:一个应用要和网络打交道,有很多步骤需要访问网络,为了不阻塞主线程,每个步骤都创建个线程,在线程中和网络交互,用线程池就变的简单,线程池是对线程的一种封装,

杨伟乔-一个极客的世界 918

池化技术(对象池)

池化技术是一种很常见的编程技巧,目的在于提前创建如内存,对象,线程资源,降低程序运行时频繁的创建销毁带来的开销。常见的有线程池,内存池,对象池等。池化技术如何提高性能,降低系统开销在实际的应用中,程序经常需要创建对象,线程和分配内存。这些设计到系统调用,系统调用会导致程序从用户态到内核态的切换会比较耗时。有了池化技术,需要用到对应的线程,对象和内存时不需要再切换上下文之需要从相应的池中获取,也不需要销毁,用完归还即可。线程池实现的原理。

weixin_43747389的博客 1339

Java池技术-对象池、连接池、线程池

概述 一个对象的生命周期大致包括三个阶段:对象的创建、对象的使用、对象的销毁。因此对象的声明周期长度可用如下表达式表示: T=T1+T2+T3,其中T1为对象的创建时间,T2为对象的使用时间,T3为对象的销毁时间,其中T2为真正有效的使用时间,而T1,T3为对象本身开销。Java采用GC对内存进行管理,当GC开始进行“垃圾对象”回收时,系统会暂停应用程序的执行。为了改善应用程序的性能,一方面应尽量...

小超人的专栏 932

对象池模式

我们先定义一个简单的对象类Object。public:Object() {我们定义一个模拟的类,用于表示一个数据库连接。public:// 构造函数:接受连接字符串并连接数据库connect();// 析构函数:断开连接// 模拟连接数据库的过程if (!// 模拟连接延迟// 断开数据库连接// 模拟执行数据库查询} else {private:// 数据库连接字符串// 连接状态标志。

ZZL优快云2017的博客 1566

对象池的介绍与使用

1. 什么是对象池 对象池,顾名思义就是一定数量的已经创建好的对象(Object)的集合。当需要创建对象时,先在池子中获取,如果池子中没有符合条件的对象,再进行创建新对象,同样,当对象需要销毁时,不做真正的销毁,而是将其setActive(false),并存入池子中。这样就避免了大量对象的创建。 2. 对象池解决什么问题? 减少频繁创建和销毁对象带来的成本,实现对象的缓存和复用,创建对象的成本比较大,并且创建比较频繁。比如线程的创建代价比较大,于是就有了常用的线程 池。对象池(模式)是一种创建型设计模式,它

Dream_bin 1万+
上一篇: Guava使用之Table
下一篇: java线程池
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值