使用Jakarta Commons Pool对象池技术
1. 为什么使用对象池技术 创建新的对象并初始化,可能会消耗很多时间。在这种对象的初始化工作中如果依赖一些rpc远程调用来创建对象,例如通过socket或者http连接远程服务资源,最典型的就是数据库服务以及远程队列(Remote Queue),建立连接 - 发送数据 -
1. 为什么使用对象池技术
创建新的对象并初始化,可能会消耗很多时间。在这种对象的初始化工作中如果依赖一些rpc远程调用来创建对象,例如通过socket或者http连接远程服务资源,最典型的就是数据库服务以及远程队列(Remote Queue),建立连接 -> 发送数据 -> 接收连接 -> 释放连接的过程无疑对于客服端来说相当繁重。在需要大量或者频繁生成这样的对象的时候,就可能会对性能造成一些不可忽略的影响。要解决这个问题在软件层面上可以使用对象池技术(Object Pooling),而Jakarta Commons Pool框架则是处理对象池化的有力外援。
2. 对象池技术解释
对象池的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。用于充当保存对象的“容器”的对象,被称为“对象池”(Object Pool,或简称Pool)。
并非所有对象都适合拿来池化――因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。
3. Jakarta Commons Pool对象池框架
在该框架中,主要工作有两类对象:
PoolableObjectFactory:用于管理被池化的对象的产生、激活、挂起、校验和销毁;
ObjectPool:用于管理要被池化的对象的借出和归还,并通知PoolableObjectFactory完成相应的工作;
相应地,使用Pool框架的过程,也就划分成“创立PoolableObjectFactory”、“使用ObjectPool”两种动作。
3.1 使用PoolableObjectFactory
Pool框架利用PoolableObjectFactory来管理被池化的对象。ObjectPool的实例在需要处理被池化的对象的产生、激活、挂起、校验和销毁工作时,就会调用跟它关联在一起的PoolableObjectFactory实例的相应方法来操作。
PoolableObjectFactory是在org.apache.commons.pool包中定义的一个接口。实际使用的时候需要利用这个接口的一个具体实现。Pool框架本身没有包含任何一种PoolableObjectFactory实现,需要根据情况自行创立。
创立PoolableObjectFactory的大体步骤是:
创建一个实现了PoolableObjectFactory接口的类。
import org.apache.commons.pool.PoolableObjectFactory;
public class PoolableObjectFactorySample
implements PoolableObjectFactory {
private static int counter = 0;
}
为这个类添加一个Object makeObject()方法。这个方法用于在必要时产生新的对象。
public Object makeObject() throws Exception {
Object obj = String.valueOf(counter++);
System.err.println("Making Object " + obj);
return obj;
}
为这个类添加一个void activateObject(Object obj)方法。这个方法用于将对象“激活”――设置为适合开始使用的状态。
public void activateObject(Object obj) throws Exception {
System.err.println("Activating Object " + obj);
}
为这个类添加一个void passivateObject(Object obj)方法。这个方法用于将对象“挂起”――设置为适合开始休眠的状态。
public void passivateObject(Object obj) throws Exception {
System.err.println("Passivating Object " + obj);
}
为这个类添加一个boolean validateObject(Object obj)方法。这个方法用于校验一个具体的对象是否仍然有效,已失效的对象会被自动交给destroyObject方法销毁
public boolean validateObject(Object obj) {
boolean result = (Math.random() > 0.5);
System.err.println("Validating Object "
+ obj + " : " + result);
return result;
}
为这个类添加一个void destroyObject(Object obj)方法。这个方法用于销毁被validateObject判定为已失效的对象。
public void destroyObject(Object obj) throws Exception {
System.err.println("Destroying Object " + obj);
}
最后完成的PoolableObjectFactory类似这个样子:
import org.apache.commons.pool.PoolableObjectFactory; public class PoolableObjectFactorySample implements PoolableObjectFactory { private static int counter = 0; public Object makeObject() throws Exception { Object obj = String.valueOf(counter++); System.err.println("Making Object " + obj); return obj; } public void activateObject(Object obj) throws Exception { System.err.println("Activating Object " + obj); } public void passivateObject(Object obj) throws Exception { System.err.println("Passivating Object " + obj); } public boolean validateObject(Object obj) { /* 以1/2的概率将对象判定为失效 */ boolean result = (Math.random() > 0.5); System.err.println("Validating Object " + obj + " : " + result); return result; } public void destroyObject(Object obj) throws Exception { System.err.println("Destroying Object " + obj); } }
3.2 使用ObjectPool
有了合适的PoolableObjectFactory之后,便可以开始请出ObjectPool来与之同台演出了。
ObjectPool是在org.apache.commons.pool包中定义的一个接口,实际使用的时候也需要利用这个接口的一个具体实现。Pool框架本身包含了若干种现成的ObjectPool实现,可以直接利用。如果都不合用,也可以根据情况自行创建。具体的创建方法,可以参看Pool框架的文档和源码。
ObjectPool的使用方法类似这样:
生成一个要用的PoolableObjectFactory类的实例。
PoolableObjectFactory factory = new PoolableObjectFactorySample();
利用这个PoolableObjectFactory实例为参数,生成一个实现了ObjectPool接口的类(例如StackObjectPool)的实例,作为对象池。
ObjectPool pool = new StackObjectPool(factory);
需要从对象池中取出对象时,调用该对象池的Object borrowObject()方法。
Object obj = null;
obj = pool.borrowObject();
需要将对象放回对象池中时,调用该对象池的void returnObject(Object obj)方法。
pool.returnObject(obj);
当不再需要使用一个对象池时,调用该对象池的void close()方法,释放它所占据的资源。
pool.close();
这些操作都可能会抛出异常,需要另外处理。
比较完整的使用ObjectPool的全过程,可以参考这段代码:
import org.apache.commons.pool.ObjectPool; import org.apache.commons.pool.PoolableObjectFactory; import org.apache.commons.pool.impl.StackObjectPool; public class ObjectPoolSample { public static void main(String[] args) { Object obj = null; PoolableObjectFactory factory = new PoolableObjectFactorySample(); ObjectPool pool = new StackObjectPool(factory); try { for(long i = 0; i <p>综上,UML图如下:</p> <p><img class="alignnone size-full wp-image-944 lazy" src="/static/imghw/default1.png" data-src="http://www.68idc.cn/help/uploads/allimg/150302/10540945H-0.gif" alt="" style="max-width:90%" title="1339989089_1857" style="max-width:90%"></p> <h3 id="线程安全问题">3.3 线程安全问题</h3> <p>有时候可能要在多线程环境下使用Pool框架,这时候就会遇到和Pool框架的线程安全程度有关的问题。</p> <p>因为ObjectPool和KeyedObjectPool都是在org.apache.commons.pool中定义的接口,而在接口中无法使用“synchronized”来修饰方法,所以,一个ObjectPool下的各个方法是否是同步方法,完全要看具体的实现。而且,单纯地使用了同步方法,也并不能使对象就此在多线程环境里高枕无忧。</p> <p>就Pool框架中自带的几个ObjectPool的实现而言,它们都在一定程度上考虑了在多线程环境中使用的情况。不过还不能说它们是完全“线程安全”的。</p> <p>例如,这段代码有些时候就会有一些奇怪的表现,最后输出的结果比预期的要大:</p> <p class="wp_syntax"></p><p class="code"></p><pre class="brush:php;toolbar:false">import org.apache.commons.pool.ObjectPool; import org.apache.commons.pool.impl.StackObjectPool; class UnsafePicker extends Thread { private ObjectPool pool; public UnsafePicker(ObjectPool op) { pool = op; } public void run() { Object obj = null; try { /* 似乎…… */ if ( pool.getNumActive() <p>要避免这种情况,就要进一步采取一些措施才行:</p> <p class="wp_syntax"></p><p class="code"></p><pre class="brush:php;toolbar:false">import org.apache.commons.pool.ObjectPool; import org.apache.commons.pool.impl.StackObjectPool; class SafePicker extends Thread { private ObjectPool pool; public SafePicker(ObjectPool op) { pool = op; } public void run() { Object obj = null; try { /* 略加处理 */ synchronized (pool) { if ( pool.getNumActive() <p>基本上,可以说Pool框架是线程相容的。但是要在多线程环境中使用,还需要作一些特别的处理。</p> <h2 id="Jedis中线程池的实例">4. Jedis中线程池的实例</h2> <p>下面看一个实例,由于近期在研究Redis,所以需要找一个可靠的redis驱动,有很多开源项目,详见链接,Jedis便是其中历史较早的。相比于其他驱动,Jedis提供了一个JedisPool用于管理redis连接的池,其主要工作的包括Pool.java,JedisPool.java和JedisPoolConfig.java。</p> <p>Pool.java封装了一个GenericObjectPool,负责Jedis连接的产生、校验和销毁。</p> <p class="wp_syntax"></p><p class="code"></p><pre class="brush:php;toolbar:false">package redis.clients.util; ? import org.apache.commons.pool.PoolableObjectFactory; import org.apache.commons.pool.impl.GenericObjectPool; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisException; ? public abstract class Pool { private final GenericObjectPool internalPool; ? public Pool(final GenericObjectPool.Config poolConfig, PoolableObjectFactory factory) { this.internalPool = new GenericObjectPool(factory, poolConfig); } ? @SuppressWarnings("unchecked") public T getResource() { try { return (T) internalPool.borrowObject(); } catch (Exception e) { throw new JedisConnectionException( "Could not get a resource from the pool", e); } } ? public void returnResourceObject(final Object resource) { try { internalPool.returnObject(resource); } catch (Exception e) { throw new JedisException( "Could not return the resource to the pool", e); } } ? public void returnBrokenResource(final T resource) { returnBrokenResourceObject(resource); } ? public void returnResource(final T resource) { returnResourceObject(resource); } ? protected void returnBrokenResourceObject(final Object resource) { try { internalPool.invalidateObject(resource); } catch (Exception e) { throw new JedisException( "Could not return the resource to the pool", e); } } ? public void destroy() { try { internalPool.close(); } catch (Exception e) { throw new JedisException("Could not destroy the pool", e); } } }
JedisPool.java继承了Pool.java,内部写了一个Inner Class – BasePoolableObjectFactory,用于新建JedisPool实例时传入线程池建立、销毁、验证连接的基本方法。
package redis.clients.jedis; ? import org.apache.commons.pool.BasePoolableObjectFactory; import org.apache.commons.pool.impl.GenericObjectPool.Config; ? import redis.clients.util.Pool; ? public class JedisPool extends Pool { ? public JedisPool(final Config poolConfig, final String host) { this(poolConfig, host, Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE); } ? public JedisPool(String host, int port) { this(new Config(), host, port, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE); } ? public JedisPool(final String host) { this(host, Protocol.DEFAULT_PORT); } ? public JedisPool(final Config poolConfig, final String host, int port, int timeout, final String password) { this(poolConfig, host, port, timeout, password, Protocol.DEFAULT_DATABASE); } ? public JedisPool(final Config poolConfig, final String host, final int port) { this(poolConfig, host, port, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE); } ? public JedisPool(final Config poolConfig, final String host, final int port, final int timeout) { this(poolConfig, host, port, timeout, null, Protocol.DEFAULT_DATABASE); } ? public JedisPool(final Config poolConfig, final String host, int port, int timeout, final String password, final int database) { super(poolConfig, new JedisFactory(host, port, timeout, password, database)); } ? ? public void returnBrokenResource(final BinaryJedis resource) { returnBrokenResourceObject(resource); } ? public void returnResource(final BinaryJedis resource) { returnResourceObject(resource); } ? /** * PoolableObjectFactory custom impl. */ private static class JedisFactory extends BasePoolableObjectFactory { private final String host; private final int port; private final int timeout; private final String password; private final int database; ? public JedisFactory(final String host, final int port, final int timeout, final String password, final int database) { super(); this.host = host; this.port = port; this.timeout = timeout; this.password = password; this.database = database; } ? public Object makeObject() throws Exception { final Jedis jedis = new Jedis(this.host, this.port, this.timeout); ? jedis.connect(); if (null != this.password) { jedis.auth(this.password); } if( database != 0 ) { jedis.select(database); } ? return jedis; } ? public void destroyObject(final Object obj) throws Exception { if (obj instanceof Jedis) { final Jedis jedis = (Jedis) obj; if (jedis.isConnected()) { try { try { jedis.quit(); } catch (Exception e) { } jedis.disconnect(); } catch (Exception e) { ? } } } } ? public boolean validateObject(final Object obj) { if (obj instanceof Jedis) { final Jedis jedis = (Jedis) obj; try { return jedis.isConnected() && jedis.ping().equals("PONG"); } catch (final Exception e) { return false; } } else { return false; } } } }
JedisPoolConfig继承了GenericObjectPool.Config,用于指定一些线程池初始化参数。
package redis.clients.jedis; ? import org.apache.commons.pool.impl.GenericObjectPool.Config; ? /** * Subclass of org.apache.commons.pool.impl.GenericObjectPool.Config that * includes getters/setters so it can be more easily configured by Spring and * other IoC frameworks. * * Spring example: * * * * * * * For information on parameters refer to: * * http://commons.apache.org/pool/apidocs/org/apache/commons/pool/impl/ * GenericObjectPool.html */ public class JedisPoolConfig extends Config { public JedisPoolConfig() { // defaults to make your life with connection pool easier :) setTestWhileIdle(true); setMinEvictableIdleTimeMillis(60000); setTimeBetweenEvictionRunsMillis(30000); setNumTestsPerEvictionRun(-1); } ? public int getMaxIdle() { return maxIdle; } ? public void setMaxIdle(int maxIdle) { this.maxIdle = maxIdle; } ? public int getMinIdle() { return minIdle; } ? public void setMinIdle(int minIdle) { this.minIdle = minIdle; } ? public int getMaxActive() { return maxActive; } ? public void setMaxActive(int maxActive) { this.maxActive = maxActive; } ? public long getMaxWait() { return maxWait; } ? public void setMaxWait(long maxWait) { this.maxWait = maxWait; } ? public byte getWhenExhaustedAction() { return whenExhaustedAction; } ? public void setWhenExhaustedAction(byte whenExhaustedAction) { this.whenExhaustedAction = whenExhaustedAction; } ? public boolean isTestOnBorrow() { return testOnBorrow; } ? public void setTestOnBorrow(boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; } ? public boolean isTestOnReturn() { return testOnReturn; } ? public void setTestOnReturn(boolean testOnReturn) { this.testOnReturn = testOnReturn; } ? public boolean isTestWhileIdle() { return testWhileIdle; } ? public void setTestWhileIdle(boolean testWhileIdle) { this.testWhileIdle = testWhileIdle; } ? public long getTimeBetweenEvictionRunsMillis() { return timeBetweenEvictionRunsMillis; } ? public void setTimeBetweenEvictionRunsMillis( long timeBetweenEvictionRunsMillis) { this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; } ? public int getNumTestsPerEvictionRun() { return numTestsPerEvictionRun; } ? public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { this.numTestsPerEvictionRun = numTestsPerEvictionRun; } ? public long getMinEvictableIdleTimeMillis() { return minEvictableIdleTimeMillis; } ? public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; } ? public long getSoftMinEvictableIdleTimeMillis() { return softMinEvictableIdleTimeMillis; } ? public void setSoftMinEvictableIdleTimeMillis( long softMinEvictableIdleTimeMillis) { this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis; } ? }

继续阅读


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











CrystalDiskMark は、シーケンシャルおよびランダムの読み取り/書き込み速度を迅速に測定する、ハード ドライブ用の小型 HDD ベンチマーク ツールです。次に、編集者が CrystalDiskMark と Crystaldiskmark の使用方法を紹介します。 1. CrystalDiskMark の概要 CrystalDiskMark は、機械式ハード ドライブとソリッド ステート ドライブ (SSD) の読み取りおよび書き込み速度とパフォーマンスを評価するために広く使用されているディスク パフォーマンス テスト ツールです。 ). ランダム I/O パフォーマンス。これは無料の Windows アプリケーションで、使いやすいインターフェイスとハード ドライブのパフォーマンスのさまざまな側面を評価するためのさまざまなテスト モードを提供し、ハードウェアのレビューで広く使用されています。

foobar2000 は、音楽リソースをいつでも聴くことができるソフトウェアです。あらゆる種類の音楽をロスレス音質で提供します。音楽プレーヤーの強化版により、より包括的で快適な音楽体験を得ることができます。その設計コンセプトは、高度なオーディオをコンピュータ上で再生可能 デバイスを携帯電話に移植し、より便利で効率的な音楽再生体験を提供 シンプルでわかりやすく、使いやすいインターフェースデザイン 過度な装飾や煩雑な操作を排除したミニマルなデザインスタイルを採用また、さまざまなスキンとテーマをサポートし、自分の好みに合わせて設定をカスタマイズし、複数のオーディオ形式の再生をサポートする専用の音楽プレーヤーを作成します。過度の音量による聴覚障害を避けるために、自分の聴覚の状態に合わせて調整してください。次は私がお手伝いさせてください

StableDiffusion3 の論文がついに登場しました!このモデルは2週間前にリリースされ、Soraと同じDiT(DiffusionTransformer)アーキテクチャを採用しており、リリースされると大きな話題を呼びました。前バージョンと比較して、StableDiffusion3で生成される画像の品質が大幅に向上し、マルチテーマプロンプトに対応したほか、テキスト書き込み効果も向上し、文字化けが発生しなくなりました。 StabilityAI は、StableDiffusion3 はパラメータ サイズが 800M から 8B までの一連のモデルであると指摘しました。このパラメーター範囲は、モデルを多くのポータブル デバイス上で直接実行できることを意味し、AI の使用を大幅に削減します。

クラウド ストレージは今日、私たちの日常生活や仕事に欠かせない部分になっています。中国有数のクラウド ストレージ サービスの 1 つである Baidu Netdisk は、強力なストレージ機能、効率的な伝送速度、便利な操作体験により多くのユーザーの支持を得ています。また、重要なファイルのバックアップ、情報の共有、オンラインでのビデオの視聴、または音楽の聴きたい場合でも、Baidu Cloud Disk はニーズを満たすことができます。しかし、Baidu Netdisk アプリの具体的な使用方法を理解していないユーザーも多いため、このチュートリアルでは Baidu Netdisk アプリの使用方法を詳しく紹介します。まだ混乱しているユーザーは、この記事に従って詳細を学ぶことができます。 Baidu Cloud Network Disk の使用方法: 1. インストール まず、Baidu Cloud ソフトウェアをダウンロードしてインストールするときに、カスタム インストール オプションを選択してください。

NetEase Mailbox は、中国のネットユーザーに広く使用されている電子メール アドレスとして、その安定した効率的なサービスで常にユーザーの信頼を獲得してきました。 NetEase Mailbox Master は、携帯電話ユーザー向けに特別に作成された電子メール ソフトウェアで、電子メールの送受信プロセスが大幅に簡素化され、電子メールの処理がより便利になります。 NetEase Mailbox Master の使い方と具体的な機能について、以下ではこのサイトの編集者が詳しく紹介しますので、お役に立てれば幸いです。まず、モバイル アプリ ストアで NetEase Mailbox Master アプリを検索してダウンロードします。 App Store または Baidu Mobile Assistant で「NetEase Mailbox Master」を検索し、画面の指示に従ってインストールします。ダウンロードとインストールが完了したら、NetEase の電子メール アカウントを開いてログインします。ログイン インターフェイスは次のとおりです。

MetaMask (中国語ではリトル フォックス ウォレットとも呼ばれます) は、無料で評判の高い暗号化ウォレット ソフトウェアです。現在、BTCC は MetaMask ウォレットへのバインドをサポートしており、バインド後は MetaMask ウォレットを使用してすぐにログイン、値の保存、コインの購入などが可能になり、初回バインドで 20 USDT のトライアル ボーナスも獲得できます。 BTCCMetaMask ウォレットのチュートリアルでは、MetaMask の登録方法と使用方法、および BTCC で Little Fox ウォレットをバインドして使用する方法を詳しく紹介します。メタマスクウォレットとは何ですか? 3,000 万人を超えるユーザーを抱える MetaMask Little Fox ウォレットは、現在最も人気のある暗号通貨ウォレットの 1 つです。無料で使用でき、拡張機能としてネットワーク上にインストールできます。

Appleは火曜日にiOS 17.4アップデートを公開し、iPhoneに多数の新機能と修正をもたらした。このアップデートには新しい絵文字が含まれており、EU ユーザーは他のアプリ ストアから絵文字をダウンロードすることもできます。さらに、このアップデートでは iPhone のセキュリティ制御も強化され、より多くの「盗難デバイス保護」設定オプションが導入され、ユーザーにより多くの選択肢と保護が提供されます。 「iOS17.3では、「盗難デバイス保護」機能が初めて導入され、ユーザーの機密情報のセキュリティが強化されています。ユーザーが自宅やその他の身近な場所から離れている場合、この機能ではユーザーは最初に生体認証情報を入力する必要がありますApple ID パスワードの変更や盗難デバイス保護の無効化など、特定のデータにアクセスして変更するには、情報を再度入力する必要があります。

この論文では、自動運転においてさまざまな視野角 (遠近法や鳥瞰図など) から物体を正確に検出するという問題、特に、特徴を遠近法 (PV) 空間から鳥瞰図 (BEV) 空間に効果的に変換する方法について検討します。 Visual Transformation (VT) モジュールを介して実装されます。既存の手法は、2D から 3D への変換と 3D から 2D への変換という 2 つの戦略に大別されます。 2D から 3D への手法は、深さの確率を予測することで高密度の 2D フィーチャを改善しますが、特に遠方の領域では、深さ予測に固有の不確実性により不正確さが生じる可能性があります。 3D から 2D への方法では通常、3D クエリを使用して 2D フィーチャをサンプリングし、Transformer を通じて 3D と 2D フィーチャ間の対応のアテンション ウェイトを学習します。これにより、計算時間と展開時間が増加します。
