并发加对象锁

在本文中,我们将介绍如何在Java中创建对象池。 近年来,JVM的性能成倍增加,大多数类型的对象几乎都变得多余,从而提高了对象池的性能。 从本质上讲,对象的创建不再像以前那样昂贵。

但是,有些对象在创建时肯定会付出高昂的代价。 诸如线程,数据库连接对象之类的对象不是轻量级对象,并且创建起来稍微贵一些。 在任何应用程序中,我们都需要使用上述多种对象。 因此,如果有一种非常容易的方法可以轻松创建和维护该类型的对象池,那么可以动态使用和重用对象,而不必担心客户端代码对对象生命周期的影响,那就太好了。
在实际编写对象池的代码之前,让我们首先确定任何对象池必须回答的主要要求。

  • 池必须允许客户端使用对象(如果有)。
  • 一旦客户端将对象返回到池中,它就必须重用这些对象。
  • 如果需要,它必须能够创建更多对象以满足客户不断增长的需求。
  • 它必须提供适当的关闭机制,以便在关闭时不会发生内存泄漏。

毋庸置疑,以上几点将构成我们向客户公开的界面的基础。
因此,我们的接口声明如下:

package com.test.pool;/*** Represents a cached pool of objects.* * @author Swaranga** @param < T > the type of object to pool.*/
public interface Pool< T >
{/*** Returns an instance from the pool. * The call may be a blocking one or a non-blocking one * and that is determined by the internal implementation.* * If the call is a blocking call, * the call returns immediately with a valid object * if available, else the thread is made to wait * until an object becomes available.* In case of a blocking call, * it is advised that clients react * to {@link InterruptedException} which might be thrown* when the thread waits for an object to become available.* * If the call is a non-blocking one, * the call returns immediately irrespective of * whether an object is available or not.* If any object is available the call returns it * else the call returns < code >null< /code >.* * The validity of the objects are determined using the* {@link Validator} interface, such that * an object < code >o< /code > is valid if * < code > Validator.isValid(o) == true < /code >.* * @return T one of the pooled objects.*/T get();/*** Releases the object and puts it back to the pool.* * The mechanism of putting the object back to the pool is* generally asynchronous, * however future implementations might differ.* * @param t the object to return to the pool*/void release(T t);/*** Shuts down the pool. In essence this call will not * accept any more requests * and will release all resources.* Releasing resources are done * via the < code >invalidate()< /code >* method of the {@link Validator} interface.*/void shutdown();
}

上面的接口特意变得非常简单和通用,以支持任何类型的对象。 它提供了从池中获取对象或将对象返回池中的方法。 它还提供了一种关闭机制来处理对象。

现在,我们尝试创建上述接口的实现。 但是在此之前,必须注意,理想的release()方法将首先尝试检查客户端返回的对象是否仍然可重用,这一点很重要。 如果是,则它将返回到池,否则必须丢弃该对象。 我们希望Pool接口的每个实现都遵循此规则。 因此,在创建具体的实现之前,我们创建一个抽象的实现帽子,将这种限制强加给后续的实现。 我们的抽象实现将被称为Surprise,AbstractPool,其定义如下:

package com.test.pool;/*** Represents an abstract pool, that defines the procedure* of returning an object to the pool.* * @author Swaranga** @param < T > the type of pooled objects.*/
abstract class AbstractPool < T > implements Pool < T >
{/*** Returns the object to the pool. * The method first validates the object if it is* re-usable and then puts returns it to the pool.* * If the object validation fails, * some implementations* will try to create a new one * and put it into the pool; however * this behaviour is subject to change * from implementation to implementation* */@Overridepublic final void release(T t){if(isValid(t)){returnToPool(t);}else{handleInvalidReturn(t);}}protected abstract void handleInvalidReturn(T t);protected abstract void returnToPool(T t);protected abstract boolean isValid(T t);
}

在上面的类中,我们强制对象池必须先验证对象,然后再将其返回到池中。 为了自定义其池的行为,实现可以自由选择它们实现三种抽象方法的方式。 他们将决定使用自己的逻辑,如何检查对象是否对重用有效[validate()方法,如果客户端返回的对象无效[该方法,handleInvalidReturn()方法]和实际逻辑,该怎么办将有效对象返回到池中[returnToPool()方法)。

现在有了上面的类集,我们几乎可以进行具体的实现了。 但是要注意的是,由于上述类旨在支持通用对象池,因此上述类的通用实现将不知道如何验证对象[因为对象将是通用的:-)。 因此,我们需要其他可以帮助我们的东西。

我们实际上需要的是一种验证对象的通用方法,这样,具体的Pool实现就不必担心正在验证的对象的类型。 因此,我们引入了一个新的接口Validator,该接口定义了验证对象的方法。 我们对Validator接口的定义如下:

package com.test.pool;/*** Represents the functionality to * validate an object of the pool* and to subsequently perform cleanup activities.* * @author Swaranga** @param < T > the type of objects to validate and cleanup.*/public static interface Validator < T >{/*** Checks whether the object is valid.* * @param t the object to check.* * @return true * if the object is valid else false .*/public boolean isValid(T t);/*** Performs any cleanup activities * before discarding the object.* For example before discarding * database connection objects,* the pool will want to close the connections. * This is done via the * invalidate() method.* * @param t the object to cleanup*/public void invalidate(T t);}

上面的接口定义了检查对象是否有效的方法,以及使对象无效的方法。 当我们要丢弃对象并清除该实例使用的任何内存时,应使用invalidate方法。 注意,此接口本身没有什么意义,仅在对象池的上下文中使用时才有意义。 因此,我们在顶级Pool接口中定义此接口。 这类似于Java Collections库中的Map和Map.Entry接口。 因此,我们的Pool接口如下所示:

package com.test.pool;/*** Represents a cached pool of objects.* * @author Swaranga** @param < T > the type of object to pool.*/
public interface Pool< T >
{/*** Returns an instance from the pool. * The call may be a blocking one or a non-blocking one * and that is determined by the internal implementation.* * If the call is a blocking call, * the call returns immediately with a valid object * if available, else the thread is made to wait * until an object becomes available.* In case of a blocking call, * it is advised that clients react * to {@link InterruptedException} which might be thrown* when the thread waits for an object to become available.* * If the call is a non-blocking one, * the call returns immediately irrespective of * whether an object is available or not.* If any object is available the call returns it * else the call returns < code >null< /code >.* * The validity of the objects are determined using the* {@link Validator} interface, such that * an object < code >o< /code > is valid if * < code > Validator.isValid(o) == true < /code >.* * @return T one of the pooled objects.*/T get();/*** Releases the object and puts it back to the pool.* * The mechanism of putting the object back to the pool is* generally asynchronous, * however future implementations might differ.* * @param t the object to return to the pool*/void release(T t);/*** Shuts down the pool. In essence this call will not * accept any more requests * and will release all resources.* Releasing resources are done * via the < code >invalidate()< /code >* method of the {@link Validator} interface.*/void shutdown();/*** Represents the functionality to * validate an object of the pool* and to subsequently perform cleanup activities.* * @author Swaranga** @param < T > the type of objects to validate and cleanup.*/public static interface Validator < T >{/*** Checks whether the object is valid.* * @param t the object to check.* * @return true * if the object is valid else false .*/public boolean isValid(T t);/*** Performs any cleanup activities * before discarding the object.* For example before discarding * database connection objects,* the pool will want to close the connections. * This is done via the * invalidate() method.* * @param t the object to cleanup*/public void invalidate(T t);}
}

我们几乎准备好具体实施了。 但是在此之前,我们需要一种最终的武器,它实际上是对象池中最重要的武器。 这被称为“创建新对象的能力”。c我们的对象池将是通用的,它们必须具有如何创建新对象以填充其池的知识。 此功能也必须不依赖于对象池的类型,并且必须是创建新对象的常用方法。 完成此操作的方法将是一个称为ObjectFactory的接口,该接口仅定义一种方法,即“如何创建新对象”。 我们的ObjectFactory接口如下:

package com.test.pool;/*** Represents the mechanism to create * new objects to be used in an object pool.* * @author Swaranga** @param < T > the type of object to create. */
public interface ObjectFactory < T >
{/*** Returns a new instance of an object of type T.* * @return T an new instance of the object of type T*/public abstract T createNew();
}

最后,我们完成了我们的帮助程序类,现在我们将创建Pool接口的具体实现。 因为我们想要一个可以在并发应用程序中使用的池,所以我们将创建一个阻塞池,如果该池中没有可用的对象,它将阻塞客户端。 阻塞机制将无限期阻塞,直到对象可用为止。 这种实现方式引起了另一种方法,该方法将仅在给定的超时时间段内阻塞,如果在返回该对象的超时之前有任何对象可用,否则在超时之后而不是永远等待,则返回空对象。 此实现类似于Java Concurrency API的LinkedBlockingQueue实现,因此在实现实际的类之前,我们公开另一个实现BlockingPool,该实现类似于Java Concurrency API的BlockingQueue接口。

因此,Blockingpool接口声明如下:

package com.test.pool;import java.util.concurrent.TimeUnit;/*** Represents a pool of objects that makes the * requesting threads wait if no object is available.* * @author Swaranga** @param < T > the type of objects to pool.*/
public interface BlockingPool < T > extends Pool < T >
{/*** Returns an instance of type T from the pool.* * The call is a blocking call, * and client threads are made to wait* indefinitely until an object is available. * The call implements a fairness algorithm * that ensures that a FCFS service is implemented.* * Clients are advised to react to InterruptedException. * If the thread is interrupted while waiting * for an object to become available,* the current implementations * sets the interrupted state of the thread * to true and returns null. * However this is subject to change * from implementation to implementation.* * @return T an instance of the Object * of type T from the pool.*/T get();/*** Returns an instance of type T from the pool, * waiting up to the* specified wait time if necessary * for an object to become available..* * The call is a blocking call, * and client threads are made to wait* for time until an object is available * or until the timeout occurs. * The call implements a fairness algorithm * that ensures that a FCFS service is implemented.* * Clients are advised to react to InterruptedException. * If the thread is interrupted while waiting * for an object to become available,* the current implementations * set the interrupted state of the thread * to true and returns null. * However this is subject to change * from implementation to implementation.*  * * @param time amount of time to wait before giving up, *   in units of unit* @param unit a TimeUnit determining *   how to interpret the*        timeout parameter*        * @return T an instance of the Object * of type T from the pool.*        * @throws InterruptedException * if interrupted while waiting*/T get(long time, TimeUnit unit) throws InterruptedException;
}

我们的BoundedBlockingPool实现将如下所示:

package com.test.pool;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;public final class BoundedBlockingPool < T > extends AbstractPool < T >implements BlockingPool < T >
{private int size;private BlockingQueue < T > objects;private Validator < T > validator;private ObjectFactory < T > objectFactory;private ExecutorService executor = Executors.newCachedThreadPool();private volatile boolean shutdownCalled;public BoundedBlockingPool(int size, Validator < T > validator, ObjectFactory < T > objectFactory){super();this.objectFactory = objectFactory;this.size = size;this.validator = validator;objects = new LinkedBlockingQueue < T >(size);initializeObjects();shutdownCalled = false;}public T get(long timeOut, TimeUnit unit){if(!shutdownCalled){T t = null;try{t = objects.poll(timeOut, unit);return t;}catch(InterruptedException ie){Thread.currentThread().interrupt();}return t;}throw new IllegalStateException('Object pool is already shutdown');}public T get(){if(!shutdownCalled){T t = null;try{t = objects.take();}catch(InterruptedException ie){Thread.currentThread().interrupt();}return t;}throw new IllegalStateException('Object pool is already shutdown');}public void shutdown(){shutdownCalled = true;executor.shutdownNow();clearResources();}private void clearResources(){for(T t : objects){validator.invalidate(t);}}@Overrideprotected void returnToPool(T t){if(validator.isValid(t)){executor.submit(new ObjectReturner(objects, t));}}@Overrideprotected void handleInvalidReturn(T t){}@Overrideprotected boolean isValid(T t){return validator.isValid(t);}private void initializeObjects(){for(int i = 0; i < size; i++){objects.add(objectFactory.createNew());}}private class ObjectReturner < E > implements Callable < Void >{private BlockingQueue < E > queue;private E e;public ObjectReturner(BlockingQueue < E > queue, E e){this.queue = queue;this.e = e;}public Void call(){while(true){try{queue.put(e);break;}catch(InterruptedException ie){Thread.currentThread().interrupt();}}return null;}}
}

上面是一个非常基本的对象池,在内部由LinkedBlockingQueue支持。 唯一感兴趣的方法是returnToPool()方法。 由于内部存储是一个阻塞池,因此如果我们尝试将返回的元素直接放入LinkedBlockingPool中,则如果队列已满,它可能会阻塞客户端。 但是我们不希望对象池的客户端仅为了执行普通任务(例如将对象返回到池)而阻塞。 因此,我们已经完成了将对象作为异步任务插入LinkedBlockingQueue的实际任务,并将其提交给Executor实例,以便客户端线程可以立即返回。

现在,我们将上述对象池用于代码中。 我们将使用对象池来池一些数据库连接对象。 因此,我们将需要一个验证器来验证我们的数据库连接对象。

我们的JDBCConnectionValidator将如下所示:

package com.test;import java.sql.Connection;
import java.sql.SQLException;import com.test.pool.Pool.Validator;public final class JDBCConnectionValidator implements Validator < Connection >
{public boolean isValid(Connection con){ if(con == null){return false;}try{return !con.isClosed();}catch(SQLException se){return false;}}public void invalidate(Connection con){try{con.close();}catch(SQLException se){}}
}

我们的JDBCObjectFactory将使对象池能够创建新对象,如下所示:

package com.test;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;import com.test.pool.ObjectFactory;public class JDBCConnectionFactory implements ObjectFactory < Connection >
{private String connectionURL;private String userName;private String password;public JDBCConnectionFactory(String driver, String connectionURL, String userName, String password){super();try{Class.forName(driver);}catch(ClassNotFoundException ce){throw new IllegalArgumentException('Unable to find driver in classpath', ce);}this.connectionURL = connectionURL;this.userName = userName;this.password = password;}public Connection createNew(){ try{return DriverManager.getConnection(connectionURL, userName, password);}catch(SQLException se){throw new IllegalArgumentException('Unable to create new connection', se);}}
}

现在,我们使用上面的Validator和ObjectFactory创建一个JDBC对象池:

package com.test;
import java.sql.Connection;import com.test.pool.Pool;
import com.test.pool.PoolFactory;public class Main
{public static void main(String[] args){Pool < Connection > pool = new BoundedBlockingPool < Connection > (10, new JDBCConnectionValidator(),new JDBCConnectionFactory('', '', '', ''));//do whatever you like}
}

作为阅读整个帖子的奖励。 我将提供Pool接口的另一种实现,它实际上是一个非阻塞对象池。 此实现与上一个实现的唯一区别是,如果某个元素不可用,则此实现不会阻塞客户端,而是返回null。 它去了:

package com.test.pool;import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;public class BoundedPool < T > extends AbstractPool < T >
{private int size;private Queue < T > objects;private Validator < T > validator;private ObjectFactory < T > objectFactory;private Semaphore permits;private volatile boolean shutdownCalled;public BoundedPool(int size, Validator < T > validator, ObjectFactory < T > objectFactory){super();this.objectFactory = objectFactory;this.size = size;this.validator = validator;objects = new LinkedList < T >();initializeObjects();shutdownCalled = false;}@Overridepublic T get(){T t = null;if(!shutdownCalled){if(permits.tryAcquire()){t = objects.poll();}}else{throw new IllegalStateException('Object pool already shutdown');}return t;}@Overridepublic void shutdown(){shutdownCalled = true;clearResources();}private void clearResources(){for(T t : objects){validator.invalidate(t);}}@Overrideprotected void returnToPool(T t){boolean added = objects.add(t);if(added){permits.release();}}@Overrideprotected void handleInvalidReturn(T t){}@Overrideprotected boolean isValid(T t){return validator.isValid(t);}private void initializeObjects(){for(int i = 0; i < size; i++){objects.add(objectFactory.createNew());}}
}

考虑到我们现在有两个强大的实现,最好让用户通过带有有意义名称的工厂创建我们的池。 这是工厂:

package com.test.pool;import com.test.pool.Pool.Validator;/*** Factory and utility methods for * {@link Pool} and {@link BlockingPool} classes * defined in this package. * This class supports the following kinds of methods:**
  • *
  • 创建并返回{@link Pool}接口的默认非阻塞*实现的方法。 *
  • * *
  • 创建并返回{@link BlockingPool}接口的默认实现的方法。 *
  • *

* * @author Swaranga * /公共最终类PoolFactory {private PoolFactory(){} / ** *创建一个并返回一个新的对象池,该对象池是{@link BlockingPool}的一个实现,其大小受以下限制: * size参数。 * * @param size池中对象的数量。 * @param factory工厂创建新对象。 * @param Validator验证器,用于验证返回对象的可重用性。 * * @返回一个受限制的对象池*由大小限制* / public static <T> Pool <T> newBoundedBlockingPool(int size,ObjectFactory <T> factory,Validator <T> validator){返回新的BoundedBlockingPool <T>(size,验证人,工厂); } / ** *创建一个并返回一个新的对象池,该对象池是{@link Pool}的一个实现,该对象的大小受size参数限制。 * * @param size池中对象的数量。 * @param factory工厂创建新对象。 * @paramvalidator验证器,以验证*返回对象的可重用性。 * * @返回一个受大小限制的对象池* / public static <T> Pool <T> newBoundedNonBlockingPool(int size,ObjectFactory <T> factory,Validator <T> validator){返回新的BoundedPool <T>(大小,验证器,厂); }}

因此,我们的客户现在可以以更易读的方式创建对象池:

package com.test;
import java.sql.Connection;import com.test.pool.Pool;
import com.test.pool.PoolFactory;public class Main
{public static void main(String[] args){Pool < Connection > pool = PoolFactory.newBoundedBlockingPool(10, new JDBCConnectionFactory('', '', '', ''), new JDBCConnectionValidator());//do whatever you like}
}

这样就结束了我们的长篇文章。 这个早就该了。 随时使用,更改,添加更多实现。

祝您编程愉快,别忘了分享!

参考: Java HotSpot博客上的JCG合作伙伴 Sarma Swaranga 提供的通用并发对象池 。

翻译自: https://www.javacodegeeks.com/2012/09/a-generic-and-concurrent-object-pool.html

并发加对象锁

并发加对象锁_通用并发对象池相关推荐

  1. java 对象锁_个人对java中对象锁与类锁的一些理解与实例

    一  什么是对象锁 对象锁也叫方法锁,是针对一个对象实例的,它只在该对象的某个内存位置声明一个标识该对象是否拥有锁,所有它只会锁住当前的对象,而并不会对其他对象实例的锁产生任何影响,不同对象访问同一个 ...

  2. java 对象压缩_理解Java对象:要从内存布局及底层机制说起,话说....

    前言 大家好,又见面了,今天是JVM专题的第二篇文章,在上一篇文章中我们说了Java的类和对象在JVM中的存储方式,并使用HSDB进行佐证,没有看过上一篇文章的小伙伴可以点这里:< 这篇文章主要 ...

  3. mysql如何加悲观锁_【mysql】关于悲观锁

    关于mysql中的锁 在并发环境下,有可能会出现脏读(Dirty Read).不可重复读(Unrepeatable Read). 幻读(Phantom Read).更新丢失(Lost update)等 ...

  4. mysql事务怎么加排他锁_八种方法实现CSS页面底部固定 - SegmentFault 思否

    共享锁.排他锁 InnoDB 实现了两种类型的锁机制:共享锁(S)和排他锁(X).共享锁允许一个事务读数据,不允许修改数据,如果其他事务要再对该行加锁,只能加共享锁:排他锁是修改数据时加的锁,可以读取 ...

  5. 声明对象 创建对象_流利的对象创建

    声明对象 创建对象 关于此主题的文章很多(绝大多数),但我只是想贡献我的两分钱,并写一篇简短的文章,介绍如何使用Java中的Fluent Object Creation模式或对象构建器实例化Value ...

  6. python 对象锁_也许你对 Python GIL 锁的理解是 错的。

    摄影:产品经理甜白与草莓更配~ 我刚到现在这个公司时,听到当时一个高级工程师(现已离职)大声地跟他旁边的同事说:  Python 有 GIL 锁,所以它的多线程实际上是单线程,所以写多线程代码不用考 ...

  7. wait放弃对象锁_终于搞懂了sleep/wait/notify/notifyAll,真的是不容易

    sleep/wait/notify/notifyAll分别有什么作用?它们的区别是什么?wait时为什么要放在循环里而不能直接用if? 简介 首先对几个相关的方法做个简单解释,Object中有几个用于 ...

  8. 线程池传递对象参数_一次线程池参数错误引起的线上故障

    在JAVA里,我们通常会把没有前后依赖关系的逻辑操作扔到多个线程里并行执行,以提高代码运行效率. 同时,我们一般也不会单独显式创建线程,而是通过线程池设置线程.使用线程池的好处是减少在创建和销毁线程上 ...

  9. mysql高并发和大流量_高并发-高并发和大流量解决方案

    高并发架构相关概念 并发 并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,并且这几个程序都是在同一个处理机上运行,担任一个时刻点上只有一个程序在处理机上运行. 我们所说的 ...

最新文章

  1. iptables防DDOS***和CC***设置
  2. 2008年CCNA第三学期第一单元中文题目(2008-12-21 18:30:01
  3. 剑指offer 第一章 面试的流程
  4. linux top 命令可视化_linux性能监控:CPU监控命令之top命令
  5. C++语言函数重载详解和示例
  6. 测试用例的八大设计方法
  7. Python中fastapi构建的web项目使用pyinstaller打包为exe文件
  8. SpringBoot引入Redis
  9. 遍历Map集合的4种常用方法
  10. tomcat6到tomcat9解压版(64位)随意下载
  11. android制作图矢量图的工具,矢量图形绘图工具——PaintCode
  12. 使用screw生成数据库文档
  13. 暨南大学计算机系录取分数线,暨南大学2017年在广东省各专业录取分数线
  14. 在你的 Android 手机上「云养猫」:Android 11 Beta 3 具透
  15. PostgreSQL下载、安装和配置使用
  16. ensp-VRRP的配置
  17. vector中push_back和emplace_back区别
  18. vue 获取当前本机ip_vue中获取本地ip
  19. word-wrap控制长单词或URL地址换行
  20. 镜像网络MW受邀亮相巴比特杭州区块链国际周

热门文章

  1. 一张图告诉你为什么是服务网关
  2. 又一大波笑到肾抽筋,笑出六块腹肌的段子
  3. 计算机网络产生的历史背景,网络技术背景及sdn概述.pdf
  4. org.apache.kafka.common.errors.TimeoutException: Topic not present in metadata 解决方法
  5. jvm(4)-虚拟机性能监控与故障处理工具
  6. 网络——连接到server
  7. MySQL基础---增删改查语法
  8. java.线程池 线程数_如何在线程“ main”中修复异常java.lang.NoClassDefFoundError:Java中的org / slf4j / LoggerFactory...
  9. travis-ci_使用Travis-CI的SpringBoot应用程序的CI / CD
  10. java中regex_Java 9中的新Regex功能