2016-09-01 9 views
1

以下の2つのサンプルクラスでは、どのような機能的な違いがあるのだろうかと思います。どのスタイルを別のスタイルより優先すべきか、そしてその理由。スレッドセーフなクラスを定義する2つの方法の違い

public class MyQueue { 
    private Queue<Abc> q; 

    public MyQueue() { 
     q = Collections.synchronizedList(new LinkedList<Abc>()); 
    } 

    public void put(Abc obj) { 
     q.add(obj); 
    } 

    public Abc get() { 
     return q.remove(); 
    } 
} 

OR

public class MyQueue { 
    private Queue<Abc> q; 

    public MyQueue() { 
     q = new LinkedList<Abc>(); 
    } 

    public synchronized void put(Abc obj) { 
     q.add(obj); 
    } 

    public synchronized Abc get() { 
     return q.remove(); 
    } 
} 

私のテイクがある - の両方がクラスでこれだけの機能は、個人の好みの問題だけ限り完全に正常に動作します。

それ以上の違いがある場合はお知らせください。

+0

この単純化されたケースでは、 'synchronizedList()'が 'LinkedList'の周りにラッパーを追加する点を除いてほとんど違いはありません。したがって、すべての呼び出しは委譲する必要があります。 2番目のバージョンには、メソッド委任の余分なレイヤーがありません。 – Andreas

答えて

2

主なアーキテクチャ上の違いは、2番目の実装では同期モニタ(オブジェクト自体)が外部に公開されている点です。それは誰もが潜在的にあなたが内部同期に使用するのと同じロックを取得できることを意味します

MyQueue myQueue = new MyQueue(); // a shared instance 

synchronized(myQueue) { 
    // No one else can call synchronized methods while you're here 
} 

それは利益をもたらすか、自分のクラスのユースケースに応じて、問題を引き起こす可能性があります。

最初の実装で同期の詳細が隠れているという事実により、将来的には新しい機能を追加するための柔軟性が少し向上します(必要な場合はput()get()メソッドに同期されていないコードを追加できます)。あなたのリストの周りに追加のレイヤーを持っているというマイナーなペナルティが伴います。

これ以外の点では、提示された機能に違いはありません。

PS:q宣言にfinalを追加することを忘れないでください。それ以外のクラスでは、という安全な発行が保証されず、完全にスレッドセーフであるとは限りません。

+0

私はロックを公開することが好きだったので、基本的に私の追加、削除は外部同期ブロックと同期することができます。 –

0

リストの場合、ラッパーを使用してアクセスするか、同期ブロックを使用してアクセスするたびにガードするかの間に、機能に違いはありません。

しかし、ConcurrentHashMapの場合のように、ラッパーによって提供される同期メカニズムを使用する方が良い場合があります。

たとえば、スレッドセーフではない単純なHashMapへのアクセスを自分自身で保護する場合は、マップ上のすべてのキー(すべてのキー)を読み書きするためにロックし、マップ上の並行性に影響します。 ConcurrentHashMapではマップのキーセットのみをロックするため、リード/ライト同時操作でパフォーマンスを向上させることができます。

ありがとうございます!

関連する問題