Java併発(二)現代同時応用の部材


「仕事をよくしようとするなら、まずその器を利する」ということわざがあります。複数スレッド同時システムを作成するには、我々のsychironizton aidとして良いパッケージが必要です。java.util.co ncurrentパッケージの下には多くのパッケージがあります。多くのスレッドを書いてくれるシステムの新しいツールがあります。
一、原子類:java.util.co ncurrent.atomic
    AtomicInteger、AtomicLong、AtomicBoolean、AtomicReference。それらの意味は基本的にvolatileと同じで、一つのAPIにパッケージされているにすぎません。このAPIは操作のための適切な原子方法を含みます。これらの実装を作成する際に近代的なプロセッサの特性を利用しているので、ハードウェアおよびオペレーティングシステムから適切なサポートが得られるならば、それらは非ブロッキング(スレッドロックを必要としない)であってもよい。Java言語では、+iとi++の操作はスレッドの安全ではなく、使用時には、避けられないsynchronizedのキーワードを使用して、AtomicIntegerやAtomicLong上の原子操作getAndIncrement()の方法で解決されました。
   注:原子類は似たような名前のクラスから継承されていないので、アトミックBooleanはBooleanとしては使えません。
二、スレッドロック:java.util.co ncurrent.locks
  sychronized同期方式はロックという簡単な概念に基づいており、この方法にはいくつかの欠点がある。
  • 錠は一つのタイプだけです。
  • は、ロックされたオブジェクトに対して同期動作が同じ作用です。
  • は、同期コードブロックまたは方法の開始時にスレッドロックを取得し、終了時にスレッドロック
  • を解放する。
  • スレッドがロックされたり、ブロックされたりします。他の可能性はありません。
    スレッドロックに対するサポートを再構築すれば、いくつかのアップグレードが可能です。
  • は、異なるタイプのロック
  • を追加します。
  • は、ロックのブロックを制限せず、すなわち、一つの方法でロックを解除することができる。
  • スレッドがロックされていない場合、スレッドが後退または実行されることができます。
  • は、スレッドがロック解除を試みることを許可し、待ち時間を超えた後に
  • を放棄することができる。
    ロックインターフェースのいくつかの実装クラス:
  • Rentrant Lock:本質的には同期ブロックに使用されるロックと同じですが、それはやや柔軟です。
  • Reentrant ReadWriteLock.ReadLock(静的内部クラス)
  • Reentrant ReadWriteLock.WriteLock(静的内部クラス)
  • ロック類の具体的な使い方はインターネットで調べたり、ヘルプ文書を見たりできます。ここでは書きません。
     
    三、CountDown Latch
         JDK 1.5 APIの中国語版の解釈は、「同期補助類は、他のスレッドで実行されている一連の操作を完了する前に、一つ以上のスレッドがずっと待っていることができます。」"A synchronization aid that allows one or more threads to wait until a set of operation being performed in other threads complets."  CountDownLatchは他のスレッドがそれぞれの操作を完了するまで1つまたは複数のスレッドを待機状態にすることができます。
        具体的な使い方はヘルプ文書を見ることができます。次の例(他のブログから):
     
    public class CountDownLatchTest {
    
        //    100   ,10         ,        。          ,    。
        public static void main(String[] args) throws InterruptedException {
    
            //        
            final CountDownLatch begin = new CountDownLatch(1);  
    
            //        
            final CountDownLatch end = new CountDownLatch(10);  
    
            //      
            final ExecutorService exec = Executors.newFixedThreadPool(10);  
    
            for (int index = 0; index < 10; index++) {
                final int NO = index + 1;  
                Runnable run = new Runnable() {
                    public void run() {  
                        try {  
                            //         ,        。
                            //   
                            begin.await();  
                            Thread.sleep((long) (Math.random() * 10000));  
                            System.out.println("No." + NO + " arrived");  
                        } catch (InterruptedException e) {  
                        } finally {  
                            //          ,end   
                            end.countDown();
                        }  
                    }  
                };  
                exec.submit(run);
            }  
            System.out.println("Game Start");  
            // begin  ,    
            begin.countDown();  
            //   end  0,         
            end.await();  
            System.out.println("Game Over");  
            exec.shutdown();  
        }
    }
     
     
     三、CocurrenthashMap、CopyOWriteArayList
          ConcerenthashMapクラスは標準HashMapの同時バージョンです。Collectionクラスで提供されるSychironized Map機能を改善しました。これらの方法が戻ってくるセットに含まれるロックは必要以上です。
          CopyOWriteArayListの使い方はJavaのCopyOWrite容器を参考にして書いたほうがいいと思います。
     四、Queue
         Javaには多くのスレッドプログラムがQueに依存しています。Queはスレッド間で作業ユニットを送るためによく使われています。このモードはQueの最も簡単な同時展開BlockingQueで実現するのに適しています。
         1.Blocking Que
           BlockingQueの二つの特性:
  • がQueの中にput()を入れる時、もしQueがいっぱいになると、入れたスレッドはQueが空間
  • をあけるまで待つことになります。
  • Queからtake()を取り出す時、もしQueが空ならば、スレッドを取り出してふさがります。
         BlockingQueインターフェースの二つの基本的な実現:Linked BlockingQue、ArayBlockingQue。それらの特性と使用シーンは言わないで、名前を見れば分かります。
        2.作業ユニットの使用
         例えば、ワークユニットを表すMyAwesomeClass類があります。マルチスレッドで処理したいです。Blocking Que<MyAwesomeClass>で作業キューを表したいですが、Blocking Que<Work Unit<MyAwesomeClass>を使ってもいいですか?
    public class WorkUnit<T>
      private final T workunit;
      public WorkUnit(T workUnit){
         this.workunit=workUnit
      }
      public T getWork(){
           return workunit;
      }
      
     
      この間接参照があれば(ちょっとProxyモードの味がしますか?)、元のクラス(ここがMyAwesomeClassです)を修正しなくても追加のデータや処理方法を追加できます。
  •  テスト(オブジェクトの修正履歴を記録する)
  •  性能指標(到着時間やサービス品質など)
  • 運転時システム情報
  • BlockingQue+worknitの例:
     
    package concurrent.blockingQueue;
    
    public abstract class Pet {
    
    	protected final String name;
    	public Pet(String name) {
    		super();
    		this.name = name;
    	}
    	public abstract void examine();
    }
    
    class Cat extends Pet{
    
    	public Cat(String name) {
    		super(name);
    	}
    	@Override
    	public void examine() {
    		System.out.println("Meow!");
    	}
    }
    
    class Dog extends Pet{
    
    	public Dog(String name) {
    		super(name);
    	}
    	@Override
    	public void examine() {
    		System.out.println("Woof!");
    	}
    	
    }
     
     
    package concurrent.blockingQueue;
    //workUnit
    public class Appointment<T> {
    
    	private final T toBeSeen;
    
    	public T getPatient() {
    		return toBeSeen;
    	}
    	public Appointment(T toBeSeen) {
    		this.toBeSeen = toBeSeen;
    	}
    }
     
     
    package concurrent.blockingQueue;
    
    import java.util.concurrent.BlockingDeque;
    
    public class Veterinarian extends Thread {
    
    	protected final BlockingDeque<Appointment<Pet>> appts;
    	protected String text="";
    	protected final int restTime;
    	private boolean shutdown=false;
    	public Veterinarian(BlockingDeque<Appointment<Pet>> appts, int restTime) {
    		super();
    		this.appts = appts;
    		this.restTime = restTime;
    	}
    
    	public synchronized void shutdown(){
    		shutdown=true;
    	}
    	
    	public void run(){
    		while(!shutdown){
    			this.seePatient();
    			try {
    				Thread.sleep(restTime);
    			} catch (Exception e) {
    				shutdown=true;
    			}
    		}
    	}
    	
    	public void seePatient(){
    		try {
    			Appointment<Pet> ap=appts.take();
    			Pet patient=ap.getPatient();
    			patient.examine();
    		} catch (Exception e) {
    			shutdown=true;
    		}
    	}
    		
    }
     
     簡単なtake()とoffer()APIの他に、BlockingQueはキューと対話する他の方法を提供しています。このような制御力はもっと大きいです。タイムアウトを持って入れたり取り出したりする操作もあります。スレッドは問題が発生した時にキューとの対話から退いて、他のことに変えてもいいです。
     
    以上の内容は全部まとめました。「Javaプログラマー修練の道」を具体的に知りたいなら、深く了解したいです。