Javaマルチスレッド同時ソリューション


Javaマルチスレッド同時プログラミングには多くの異なる問題があり、主に以下の問題の応用がある.
  • マルチスレッド読み書き共有データ同期問題
  • は、データを同時読み取りし、各スレッドが読み取ったデータの整合性を維持する問題である.

  • ソリューション:
  • synchronizedキーワードとLock同時ロック:主にマルチスレッド共有データ同期の問題を解決します. 
  • ThreadLocalは主にマルチスレッドにおけるデータの同時発生による不一致の問題を解決する.

  • ThreadLocalとsynchronizedには本質的な違いがあります.
    synchronizedは、ロックのメカニズムを利用して、変数またはコードブロックを一時的に1つのスレッドしかアクセスできないようにします.
    一方、ThreadLocalは、各スレッドに変数のコピーを提供し、各スレッドがある時点で同じオブジェクトにアクセスしないようにし、複数のスレッドによるデータ共有を分離します.
    ThreadLocalとsynchronizedには本質的な違いがあります.
    synchronizedは、ロックのメカニズムを利用して、変数またはコードブロックを一時的に1つのスレッドしかアクセスできないようにします.一方、ThreadLocalは、各スレッドに変数のコピーを提供し、各スレッドがある時点で同じオブジェクトにアクセスしないようにし、複数のスレッドによるデータ共有を分離します.一方、Synchronizedは、複数のスレッド間で通信する際にデータ共有を得るために使用されます.
    ThreadLocalとsynchronizedには本質的な違いがあります.
    synchronizedは、ロックのメカニズムを利用して、変数またはコードブロックを一時的に1つのスレッドしかアクセスできないようにします.一方、ThreadLocalは、各スレッドに変数のコピーを提供し、各スレッドがある時点で同じオブジェクトにアクセスしないようにし、複数のスレッドによるデータ共有を分離します.一方、Synchronizedは、複数のスレッド間で通信する際にデータ共有を得るために使用されます.
    ThreadLocalって何?
    JDK 1.2のバージョンではjavaが提供されています.lang.ThreadLocal,ThreadLocalはマルチスレッドプログラムの同時問題を解決するために新しい考え方を提供した.このツールクラスを使用すると、美しいマルチスレッドプログラムを簡潔に作成できます.
    ThreadLocalは文字通り「ローカルスレッド」と思われがちです.実際、ThreadLocalはThreadではなく、Threadのローカル変数であり、ThreadLocalVariableと命名したほうが理解しやすいかもしれません.
    ThreadLocalを使用して変数を維持する場合、ThreadLocalは、その変数を使用するスレッドごとに独立した変数のコピーを提供するので、各スレッドは、他のスレッドに対応するコピーに影響を与えることなく、独立して自分のコピーを変更することができます.
    スレッドの観点から見ると,ターゲット変数はスレッドのローカル変数のようであり,これもクラス名の「Local」が表す意味である.
    スレッドローカル変数はJavaの新発明ではなく、IBM IBM XL FORTRANのような多くの言語では文法的にスレッドローカル変数が提供されている.Javaでは言語レベルでのサポートは提供されず、ThreadLocalのクラスを介して変相的にサポートされている.
    したがって,Javaでスレッド局所変数を記述するコードは相対的に不器用であるため,スレッド局所変数はJava開発者においてよく普及していない.
    ThreadLocalのインタフェース方法
    ThreadLocalクラスインタフェースは簡単で、4つの方法しかありません.まず、次のことを理解します.
    void set(Object value)現在のスレッドのスレッドローカル変数の値を設定します.
    public Object get()このメソッドは、現在のスレッドに対応するスレッドローカル変数を返します.
    public void remove()は、現在のスレッドのローカル変数の値を削除し、メモリの消費量を減らすためにJDK 5.0に追加されたメソッドです.スレッドが終了すると、スレッドのローカル変数が自動的にゴミに回収されるため、このメソッドを明示的に呼び出してスレッドのローカル変数を消去することは必須ではありませんが、メモリ回収の速度を速めることができます.
    protected Object initialValue()は、サブクラスを上書きするために設計されたprotectedメソッドであるスレッドローカル変数の初期値を返します.この方法は,スレッドがget()またはset(Object)を1回目に呼び出したときに実行され,1回のみ実行される遅延呼び出し方法である.ThreadLocalのデフォルトインプリメンテーションはnullを直接返します.
     
    特筆すべきは、JDK 5.0では、ThreadLocalは汎用型をサポートしており、クラス名はThreadLocalに変更されています.APIメソッドもそれに応じて調整され、新しいバージョンのAPIメソッドはvoid set(T value)、T get()およびT initialValue()である.
    ThreadLocalはどのようにして各スレッドの変数のコピーを維持しますか?実装の考え方は簡単です.ThreadLocalクラスには、各スレッドの変数コピーを格納するMapがあり、Mapの要素のキーはスレッドオブジェクトであり、値はスレッドの変数コピーに対応します.簡単な実装バージョンを提供できます.
    //     1 SimpleThreadLocal
    class SimpleThreadLocal {
        private Map valueMap = Collections.synchronizedMap(new HashMap());
        public void set(Object newValue) {
            valueMap.put(Thread.currentThread(), newValue);// ①      ,          
        }
        public Object get() {
            Thread currentThread = Thread.currentThread();
            Object o = valueMap.get(currentThread);// ②          
            if (o == null && !valueMap.containsKey(currentThread)) {// ③   Map    ,  Map
                //      。
                o = initialValue();
                valueMap.put(currentThread, o);
            }
            return o;
        }
        public void remove() {
            valueMap.remove(Thread.currentThread());
        }
        public Object initialValue() {
            return null;
        }
    }

    コードリスト9?3このThreadLocal実装バージョンは幼稚に見えますが、JDKが提供するThreadLocalクラスと実装の考え方に近いです.
    TheadLocalの例
    package threadLocalDemo;
    public class SequenceNumber {
        // ①         ThreadLocal initialValue()  ,     
        private static ThreadLocal seqNum = new ThreadLocal() {
            public Integer initialValue() {
                return 0;
            }
        };
        // ②        
        public int getNextNum() {
            seqNum.set(seqNum.get() + 1);
            return seqNum.get();
        }
        public static void main(String[] args)
        {
            SequenceNumber sn = new SequenceNumber();
            // ③ 3     sn,       
            TestClient t1 = new TestClient(sn);
            TestClient t2 = new TestClient(sn);
            TestClient t3 = new TestClient(sn);
            t1.start();
            t2.start();
            t3.start();
        }
        private static class TestClient extends Thread
        {
            private SequenceNumber sn;
            public TestClient(SequenceNumber sn) {
                this.sn = sn;
            }
            public void run()
            {
                for (int i = 0; i < 3; i++) {
                    // ④      3    
                    System.out.println("thread[" + Thread.currentThread().getName()+"] sn[" + sn.getNextNum() + "]");
                }
            }
        }
    }

    参考文献:
  • http://www.xuebuyuan.com/1628079.html

  • http://blog.sina.com.cn/s/blog_5204918b0100d044.html

  • ThreadLocalとsynchronizedには本質的な違いがあります.
    synchronizedは、ロックのメカニズムを利用して、変数またはコードブロックを一時的に1つのスレッドしかアクセスできないようにします.一方、ThreadLocalは、各スレッドに変数のコピーを提供し、各スレッドがある時点で同じオブジェクトにアクセスしないようにし、複数のスレッドによるデータ共有を分離します.一方、Synchronizedは、複数のスレッド間で通信する際にデータ共有を得るために使用されます.