javaスレッド常用工具類の簡単な使用

10656 ワード

一Timerタイマー
Timer類は、アラームという周期的に変化するもののように、タイミングタスクを完成させるための機能です。
**1一番簡単なタイマー*
二秒後には時限爆弾が爆発します。
    @Test
    public void test() {
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("     ");
            }
        },
        2000);//        
        while (true) ;//         ,         
    }
2周期的に実行するアラームを設定します。
二秒後に一つの爆弾を爆発させてから、一秒ごとに一つずつ爆発させます。
 @Test
    public void test2() {
        new Timer().schedule(new TimerTask() {
                                 @Override
                                 public void run() {
                                     System.out.println("     ");
                                 }
                             },
                2000,
                1000);//         1000ms      。
        while (true) ;
    }
注意:もし私たちがタスクを実行する場合、手動でこのタスクをキャンセルしたいなら、cancel()方法を使ってキャンセルできます。
  • は、Timerクラスでの役割は、ジョブキュー内のすべてのタスクをキャンセルすることである(一つのTimerは、複数のTimerTaskタスクを作成することができる)
  • は、TimerTaskクラスでの役割は、自身のタスクをタスクキューからキャンセルする
  • である。
    二ThreadLocalの使用
    ThreadLocalはスレッドのローカル変数を作成するクラスです。通常、私たちは変数を作成するとき、この変数は任意のスレッドによってアクセスできます。ThreadLocalクラスを使って作成された変数は、変数を作成するスレッドにしかアクセスできません。他のスレッドはアクセスできません。
    **簡単な例**
    public class _6_ThreadLocal {
        @Test
        public void test() {
            ThreadLocal local = new ThreadLocal<>();
            for (int i = 0; i < 5; ++i) {
                final int index = i;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        synchronized (_6_ThreadLocal.class){
                            System.out.println("    :" + index);
                            local.set("  " + index + "   ");
                            System.out.println(local.get());
                        }
                    }
                }).start();
            }
            while (true);
        }
    }
    
    三ThreadPoolスレッド池
    ThreadPoolは任務を処理するスレッド工場に相当します。工場内には多くのスレッド(労働者)があります。任務が来るたびに、スレッドは任務を実行します。任務が終わったらスレッド(労働者)は休みます。ThreadPoolを使用するのは、プログラムのスループットを向上させるためであり、CPUの利用効率を向上させるためである。スレッド池は病院のようなもので、最初は一定数の医者(スレッド池の容量)を募集していましたが、患者が診察に来ると、医者は患者を診断しています。すべての医者が忙しいときは、病院は余分な医者を募集します。患者が減ると、病院はそれらの医師を解任します。
    医者の診察の簡単な例
    public class _7_ThreadPool {
        public static void main(String[] args) {
            ExecutorService threadPool = Executors.newFixedThreadPool(3);//        
    //        ExecutorService threadPool = Executors.newCachedThreadPool();//                 
    //        ExecutorService threadPool = Executors.newSingleThreadExecutor();//       
            for(int i = 0; i < 10; ++i) {
                final int index = i;
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("  " + 
                    Thread.currentThread().getName() + "     " + index + "   ");
                    }
                });
            }
        }
    }
    
    
    四ロック
    ロックは、従来のスレッドのsynchronizedよりもオブジェクトに向かっており、より便利である。lockを使用すると、スレッド間相互反発の効果を達成するために複数のスレッドが実行されるコードブロックは、同じLockオブジェクトを使用しなければならない。読み書きロック:読み取りロックと書き込みロックに分けられており、複数の読み取りロックの間では互いに反発せず、読み取りロックと書き込みロックの間でも互いに反発し、書き込みロックと書き込みロックの間でも互いに反発します。
    1つの簡単なロックの例
    二つのスレッドはそれぞれの文字列を出力し続け、各スレッドは文字列の整合性を保証します。
    public class _8_Lock {
            private static  Lock lock = new ReentrantLock();//   
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        new Ouput().output("HHHHHHHHHH");
                    }
                }
            }).start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        new Ouput().output("aaaaaaaaa");
                    }
                }
            }).start();
        }
    
      static  class Ouput{
            public  void output(String name) {
                lock.lock();//  
                try {
                    for(int i = 0; i < name.length(); ++i) {
                        System.out.print(name.charAt(i));
                    }
                    System.out.println();
                }finally {
                    lock.unlock();//   
                }
            }
        }
    }
    
    2読み書きロックの例
    簡単なキャッシュ実現
    public class _9_CacheDemo {
        private Map data = new HashMap<>();
        public static void main(String[] args) {
            System.out.println(new _9_CacheDemo().getData("haha").toString());
        }
    
        private ReadWriteLock rwl = new ReentrantReadWriteLock();
        public Object getData(String key) {
            Object value = null;
            rwl.readLock().lock();
            try {
                value = data.get(key);
                if (value == null) {
                    rwl.readLock().unlock(); //       ,   readLock ,   writeLock (1)
                    rwl.writeLock().lock();
                   try {
                       if (value == null) {//   if    value,            (1)    
                           value = "hehe";
                       }
                   }finally {
                       rwl.writeLock().unlock();
                   }
                }
                rwl.readLock().lock();//   readLock     finally    unLock
            }finally {
                rwl.readLock().unlock();
            }
            return value;
        }
    }
    
    
    五コンデント
    Condationは、Objectwait()、notify()、notifyAll()方法を異なるオブジェクトに分解して、より良いものとLockを組み合わせて使用するようにします。Locksynchronizedの代わりに、ConditionObejctによって監視される方法に取って代わっている。Conditionを使用する利点は、3つのスレッドA、B、Cなどの他のスレッドを選択的に起動することができ、現在はAスレッドを実行し、最後にCスレッドを実行する必要があり、Conditionを使用すれば良く解決できることである。
    行列をブロックする例
    public class _10_Condition {
        final Lock lock = new ReentrantLock();
        final Condition fullCondition = lock.newCondition();
        final Condition emptyCondition = lock.newCondition();
    
        final Object[] datas = new Object[10];
        int putIndex, takeIndex, count;
    
        public static void main(String[] args) {
            _10_Condition condition = new _10_Condition();
    
            //     
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 50; ++i) {
                        try {
                            Thread.sleep(new Random().nextInt(2000));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        condition.put(i);
                    }
                }
            }).start();
            //     
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 50; ++i) {
                        try {
                            Thread.sleep(new Random().nextInt(2000));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        condition.get();
                    }
                }
            }).start();
        }
    
    
        public void put(Object data) {
            lock.lock();
            try {
                while (count == datas.length) { //    ,   put
                    System.out.println("the arrays is full");
                    fullCondition.await();
                }
                datas[putIndex] = data;
                System.out.println(Thread.currentThread().getName() + " put the data-------> " + data);
                ++count;
                if (++putIndex == datas.length) {
                    putIndex = 0;
                }
                emptyCondition.signal(); //       ,   take    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public Object get() {
            lock.lock();
            try {
                while (count == 0) {   //    ,   take
                    System.out.println("the arrays is empty");
                    emptyCondition.await();
                }
                Object obj = datas[takeIndex];
                System.out.println(Thread.currentThread().getName() + " get the data " + obj);
                --count;
                if (++takeIndex == datas.length) {
                    takeIndex = 0;
                }
                fullCondition.signal(); //    ,   put    
                return obj;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            return null;
        }
    }
    
    6 Semaphore
    Semaphoreは現在のアクセスの個数を維持し、同期機構を提供し、同時にアクセスする個数を制御する。SemaphoreThreadPoolは機能が似ていますが、違いがあります。
  • スレッド池が制御するのはスレッド数であり、信号量が制御するのは同時数であり、これは同じように見えるとはいえ、違いがあります。信号量の呼び出しは、数に達してもスレッドが存在します。ただ掛けられています。スレッドプールは、同時に実行するスレッドの数が固定されており、数を超えると待つしかない。
  • スレッドプールはスレッド多重である。信号量はスレッド同期
  • である。
  • スレッドプールは複数のスレッド非同期実行タスクであり、信号量は制御タスクにおけるマルチスレッド同期領域である。
  • 小例
    10スレッド、3つのピット、毎回3つのスレッドに入ることができます。残りのスレッドは待ち時間があります。スレッドが離れると、待ちスレッドが入ることができます。
    public class _10_Semaphore {
        public static void main(String[] args) {
            Semaphore sp = new Semaphore(3);
            for(int i = 0 ; i < 10; ++i) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            sp.acquire();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"  ,   " + (3 - sp.availablePermits())+"   ");
                        try {
                            Thread.sleep(new Random().nextInt(10000));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"    "+",   " + (3 - sp.availablePermits())+"   ");
                        sp.release();
                    }
                }).start();
            }
        }
    }
    
    ソースアドレス