文章
同時環境でプログラミングする場合、共有リソースへの相互に排他的なアクセスを確保するために、複数のスレッド間で操作を同期するためにロックメカニズムが必要です。ロックはパフォーマンスの損傷を引き起こす可能性があり、これはよく知られているようです。ただし、ロック自体はあまりパフォーマンスの消費をもたらさず、パフォーマンスは主にスレッドでロックを取得するプロセスです。ロックを競うスレッドは1つだけで、現時点でマルチスレッド競争がない場合、JVMは最適化し、ロックによって引き起こされるパフォーマンスの消費は基本的に無視できます。したがって、ロックの操作の標準化、ロックの使用方法の最適化、不必要なスレッド競合の回避は、プログラムのパフォーマンスを改善するだけでなく、不規則なロックとプログラムの堅牢性を改善することによって引き起こされるスレッドデッドロックの可能性を回避することもできます。以下は、いくつかのロック最適化のアイデアを説明しています。
1.メソッドをロックしないようにしてください
ロックが通常のメンバー関数に追加されると、スレッドはメソッドが配置されているオブジェクトのオブジェクトロックを取得します。この時点で、オブジェクト全体がロックされます。これはまた、このオブジェクトによって提供される複数の同期方法が異なるサービス用である場合、オブジェクト全体がロックされているため、1つのビジネスが処理されると、他の無関係なビジネススレッドも待たなければならないことを意味します。次の例はこれを示しています:
LockMethodクラスには、2つのビジネスプロセスで呼び出される2つの同期方法が含まれています。
public class lockmethod {public synchronized void busia(){for(int i = 0; i <10000; i ++){system.out.println(thread.currentthread()。 }} public synchronized void busib(){for(int i = 0; i <10000; i ++){system.out.println(thread.currentthread()。 }}}Bussaは、ビジネスを処理するために使用されるスレッドクラスであり、busia()lockmethodの方法を呼び出します。
パブリッククラスのbussbはスレッドを拡張します{lockmethod lockmethod; void deal(lockmethod lockmethod){this.lockmethod = lockmethod; } @Override public void run(){super.run(); lockmethod.busib(); }}TestLockMethodクラスは、ビジネス処理にスレッドBUSSAとBUSSBを使用します。
public class testlockmethod extends thread {public static void main(string [] args){lockmethod lockmethod = new lockmethod(); bussa bussa = new bussa(); bussb bussb = new bussb(); bussa.deal(lockmethod); bussb.deal(lockmethod); bussa.start(); bussb.start(); }}プログラムを実行すると、スレッドBussaの実行中に、bussbがbussib()にfunction bussib()に入ることができないことがわかります。
2。同期コードブロックを削減し、データのみをロックします
プログラミングの利便性のために、一部の人々は大きなコードを同期しました。このコードブロックの一部の操作が共有リソースに関連していない場合、ロックを長時間保持しないように同期ブロックの外側に配置する必要があります。特に、いくつかのサイクル操作と同期I/O操作。コードのライン範囲の同期ブロックを減らすことを意味するだけでなく、実行ロジックでも、同期ブロックを削減する必要があります。たとえば、同期後に条件付き判断を実施するのではなく、条件付き判断を追加し、同期する場合は同期し、同期ブロックに入る不要なロジックを最小限に抑えます。
3.ロックにロックを含めないようにしてください
この状況はしばしば発生します。スレッドがAロックを取得した後、同期メソッドブロック内の別のオブジェクトの同期メソッドを呼び出し、2番目のロックを取得します。これにより、コールスタック内の複数のロックリクエストが発生する可能性があります。マルチスレッドの場合、それは非常に複雑で例外の分析が困難になる可能性があり、その結果、デッドロックが生じます。次のコードはこれを示しています:
同期(a){同期(b){}}または、同期メソッドが同期ブロックで呼び出されます。
同期(a){b b = objarraylist.get(0); b.method(); //これは同期方法です}解決策は、ジャンプしてロックを追加することであり、ロックを含めないことです。
{b b = null;同期(a){b = objarraylist.get(0); } b.method();} 4.ロックを民営化し、内部でロックを管理します
ロックをプライベートオブジェクトとして使用する方が安全であり、外部から取得することはできません。オブジェクトは他のスレッドで直接ロックされる場合があり、スレッドはオブジェクトのオブジェクトロックを保持します。たとえば、:
class A {public void method1(){}} class b {public void method1(){a a = new a();同期(a){// a.method1()を直接ロックします。 }}}この方法では、オブジェクトAのオブジェクトロックは外側に保持されているため、ロックを外部の複数の場所で使用することがより危険であり、コードの論理フローを読み取るトラブルも発生します。より良い方法は、クラス内のロック自体を管理し、外部同期スキームが必要な場合にインターフェイスを介して同期操作を提供することです。
class A {private object lock = new object(); public void method1(){synchronized(lock){}}} class b {public void method1(){a a = new a(); a.method1(); }} 5.適切なロック分解を実行します
次の手順を検討してください。
public class gameserver {public map <string、list <player >> tables = new hashmap <string、list <player >>(); public void join(player player、table table){if(player.getaccountbalance()> table.getlimit()){synchronized(table){list <player> tableplayers = table.get(table.getId()); if(tableplayers.size()<9){tableplayers.add(player); }}}}}} public void reave(player player、table table){/*omit*/} public void createTable(){/*omit*/} public void destroyTable(テーブルテーブル){/*omit*/}}}}この例では、Joinメソッドは1つの同期ロックのみを使用して、テーブル内のリスト<player>オブジェクトを取得し、プレーヤーの数が9未満かどうかを判断します。テーブルに何千ものリスト<player>がある場合、テーブルロックの競争は非常に激しくなります。ここでは、ロックの分解を検討できます。データをすばやく取り出した後、リスト<player>オブジェクトをロックして、他のスレッドがすぐに競合してテーブルオブジェクトロックを取得できるようにすることができます。
パブリッククラスGameserver {
パブリックマップ<文字列、
List <player >> tables = new Hashmap <String、
list <player >>();
public void join(プレーヤープレーヤー、テーブルテーブル){
if(player.getAccountBalance()> table.getlimit()){
list <player> tableplayers = null;
同期(表){
tableplayers = tables.get(table.getid());
}
同期(TablePlayers){
if(tableplayers.size()<9){
tableplayers.add(player);
}
}
}
}
パブリックボイド休暇(プレーヤープレーヤー、テーブルテーブル){
/*省略*/
}
public void createTable(){
/*省略*/
}
public void DestroyTable(テーブルテーブル){
/*省略*/
}
}