JAvaマルチスレッド知識点まとめ

11022 ワード

マルチスレッド(英語:multithreading)
システム上で実行されているプログラムはすべてプロセスです.各プロセスには1~複数のスレッドが含まれます.スレッドはプログラム内で独立して実行でき、オペレーティングシステムが複数のスレッドのスケジューリングと実行を担当します.
スレッドとプロセスの違いは、サブプロセスと親プロセスには異なるコードとデータ空間があり、複数のスレッドはデータ空間を共有し、各スレッドには独自の実行スタックとプログラムカウンタが実行コンテキストである.マルチスレッドは主にCPU時間を節約するため、CPUの空きタイムスライスを十分に利用し、スレッドの運転中にコンピュータのメモリリソースとCPUを使用する必要がある.
メリット
・スレッドを使用して、長い時間を占有しているプログラムのタスクをバックグラウンドで処理できる
・ユーザインタフェースは、例えば、ユーザがボタンをクリックしてイベントの処理をトリガし、処理の進捗を表示するために進捗バーをポップアップすることができるように、より魅力的である
・プログラムの実行速度が速くなる可能性がある
・ユーザ入力、ファイル読み書き、ネットワーク送受信などの待機タスク実装では、スレッドが便利である.この場合、メモリ使用量などの貴重なリソースを解放できます.
欠点
・多数のスレッドがある場合、オペレーティングシステムがそれらの間を切り替える必要があるため、パフォーマンスに影響します.
・より多くのスレッドはより多くのメモリ領域を必要とする.
・スレッドは、プログラムにより多くの「バグ」をもたらす可能性があるので、注意して使用してください.
・スレッドの中止は、プログラムの実行に与える影響を考慮する必要がある.
・通常、ブロックモデルデータは複数のスレッド間で共有されており、スレッドデッドロックの発生を防止する必要がある.
JAVAでのスレッド
Javaアプリケーションは常にmain()メソッドから実行され、mian()メソッドはプライマリスレッドと呼ばれるスレッド内で実行されます.
mainメソッドも実はスレッドです.Javaではスレッドが同時に起動しているので、いつ、どれが先に実行されるかは、誰が先にCPUのリソースを得るかを完全に見ています.
 
Javaでは、プログラムが実行されるたびに少なくとも2つのスレッドが起動されます.1つはmainスレッド、1つはゴミ収集スレッドです.Javaコマンドを使用してクラスを実行するたびに、実際にはJVMが起動されるため、各jVM実習はオペレーティングシステムでプロセスを開始します.
JAvaでスレッドを作成する2つの方法:Threadの継承とRunnableインタフェースの実装
Runnableインタフェースの適用状況を実現する:
リソース共有+複数のスレッドが同じコードを実行します.
リソース共有例:チケット購入システム、複数のスレッドが共有リソースを読み書きする.
同じコードを実行する例:チケット購入システム.new Thread(obj);objはrunnableを実現するオブジェクトである.
JAvaマルチスレッドチケット購入システムコード:
class SellThread implements Runnable
         {
            int tickets=100;//        
            public synchronized void sell()//    sychronized,      
            {
                  if(tickets>0)
                  {
                     try
                     {
                        Thread.sleep(10);
                     }
                     catch(Exception e)
                     {
                        e.printStackTrace();
                     }
                  }
               }
           
         public void run()
         {
            while(true)
            {
               sell();
            }
         }
}
public class TicketSystem
{
   public static void main(String[] args)
   {
      SellThread st=new SellThread();
      new Thread(st).start();//            
      new Thread(st).start();//            
      new Thread(st).start();//            
   }
}

Threadクラスの適用を継承するには、次の手順に従います.
複数のスレッドが異なるコードを実行すると,それぞれ書き換えThreadクラスが継承される.
例えば、生産者と消費者の例です.
多くのバックグラウンドサービスプログラムの同時制御の基本原理は生産者にまとめることができる.
/
消費者モデル.
生産者消費者の例をwait()/notify()法で実現する
(コード:http://blog.csdn.net/monkey_d_meng/article/details/6251879、原作者に感謝
)
[java] view plain copy
import java.util.LinkedList;  
  
/** 
 *    Storage      
 *  
 * Email:[email protected] 
 *  
 * @author MONKEY.D.MENG 2011-03-15 
 *  
 */  
public class Storage  
{  
    //          
    private final int MAX_SIZE = 100;  
  
    //          
    private LinkedList list = new LinkedList();  
  
    //   num     
    public void produce(int num)  
    {  
        //        
        synchronized (list)  
        {  
            //             
            while (list.size() + num > MAX_SIZE)  
            {  
                System.out.println("【        】:" + num + "/t【   】:"  
                        + list.size() + "/t          !");  
                try  
                {  
                    //        ,      
                    list.wait();  
                }  
                catch (InterruptedException e)  
                {  
                    e.printStackTrace();  
                }  
            }  
  
            //          ,  num     
            for (int i = 1; i <= num; ++i)  
            {  
                list.add(new Object());  
            }  
  
            System.out.println("【       】:" + num + "/t【     】:" + list.size());  
  
            list.notifyAll();  
        }  
    }  
  
    //   num     
    public void consume(int num)  
    {  
        //        
        synchronized (list)  
        {  
            //            
            while (list.size() < num)  
            {  
                System.out.println("【        】:" + num + "/t【   】:"  
                        + list.size() + "/t          !");  
                try  
                {  
                    //        ,      
                    list.wait();  
                }  
                catch (InterruptedException e)  
                {  
                    e.printStackTrace();  
                }  
            }  
  
            //          ,  num     
            for (int i = 1; i <= num; ++i)  
            {  
                list.remove();  
            }  
  
            System.out.println("【       】:" + num + "/t【     】:" + list.size());  
  
            list.notifyAll();  
        }  
    }  
  
    // get/set    
    public LinkedList getList()  
    {  
        return list;  
    }  
  
    public void setList(LinkedList list)  
    {  
        this.list = list;  
    }  
  
    public int getMAX_SIZE()  
    {  
        return MAX_SIZE;  
    }  
}  
/** 
 *     Producer     Thread 
 *  
 * Email:[email protected] 
 *  
 * @author MONKEY.D.MENG 2011-03-15 
 *  
 */  
public class Producer extends Thread  
{  
    //            
    private int num;  
  
    //          
    private Storage storage;  
  
    //     ,      
    public Producer(Storage storage)  
    {  
        this.storage = storage;  
    }  
  
    //   run    
    public void run()  
    {  
        produce(num);  
    }  
  
    //     Storage       
    public void produce(int num)  
    {  
        storage.produce(num);  
    }  
  
    // get/set    
    public int getNum()  
    {  
        return num;  
    }  
  
    public void setNum(int num)  
    {  
        this.num = num;  
    }  
  
    public Storage getStorage()  
    {  
        return storage;  
    }  
  
    public void setStorage(Storage storage)  
    {  
        this.storage = storage;  
    }  
}  
/** 
 *     Consumer     Thread 
 *  
 * Email:[email protected] 
 *  
 * @author MONKEY.D.MENG 2011-03-15 
 *  
 */  
public class Consumer extends Thread  
{  
    //            
    private int num;  
  
    //          
    private Storage storage;  
  
    //     ,      
    public Consumer(Storage storage)  
    {  
        this.storage = storage;  
    }  
  
    //   run    
    public void run()  
    {  
        consume(num);  
    }  
  
    //     Storage       
    public void consume(int num)  
    {  
        storage.consume(num);  
    }  
  
    // get/set    
    public int getNum()  
    {  
        return num;  
    }  
  
    public void setNum(int num)  
    {  
        this.num = num;  
    }  
  
    public Storage getStorage()  
    {  
        return storage;  
    }  
  
    public void setStorage(Storage storage)  
    {  
        this.storage = storage;  
    }  
}  
/** 
 *    Test 
 *  
 * Email:[email protected] 
 *  
 * @author MONKEY.D.MENG 2011-03-15 
 *  
 */  
public class Test  
{  
    public static void main(String[] args)  
    {  
        //       
        Storage storage = new Storage();  
  
        //        
        Producer p1 = new Producer(storage);  
        Producer p2 = new Producer(storage);  
        Producer p3 = new Producer(storage);  
        Producer p4 = new Producer(storage);  
        Producer p5 = new Producer(storage);  
        Producer p6 = new Producer(storage);  
        Producer p7 = new Producer(storage);  
  
        //        
        Consumer c1 = new Consumer(storage);  
        Consumer c2 = new Consumer(storage);  
        Consumer c3 = new Consumer(storage);  
  
        //              
        p1.setNum(10);  
        p2.setNum(10);  
        p3.setNum(10);  
        p4.setNum(10);  
        p5.setNum(10);  
        p6.setNum(10);  
        p7.setNum(80);  
  
        //              
        c1.setNum(50);  
        c2.setNum(20);  
        c3.setNum(30);  
  
        //         
        c1.start();  
        c2.start();  
        c3.start();  
        p1.start();  
        p2.start();  
        p3.start();  
        p4.start();  
        p5.start();  
        p6.start();  
        p7.start();  
    }  
}  
【        】:50   【   】:0           !  
【        】:30   【   】:0           !  
【        】:20   【   】:0           !  
【       】:10    【     】:10  
【        】:20   【   】:10              !  
【        】:30   【   】:10              !  
【        】:50   【   】:10              !  
【       】:10    【     】:20  
【        】:50   【   】:20              !  
【        】:30   【   】:20              !  
【       】:20    【     】:0  
【       】:10    【     】:10  
【       】:10    【     】:20  
【       】:80    【     】:100  
【        】:10   【   】:100             !  
【       】:30    【     】:70  
【       】:50    【     】:20  
【       】:10    【     】:30  
【       】:10    【     】:40  

上記のコードを見て、
wait()/notify()
メソッド実装の同期について理解した.君は正しいかもしれない
Storage
クラスで定義する理由
public void produce(int num);
および
public void consume(int num);
なぜ生産者クラスに直接いないのか、方法が分からない.
Producer
消費者クラス
Consumer
の2つのメソッドを実装しますが、呼び出す
Storage
クラスの実装は?落ち着いて、後で説明します.私たちは先に下へ行きます.
wait()、notify()、notifyAll()は、Objectクラスに定義された3つのメソッドで、スレッドの状態を制御するために使用できます.
この3つのメソッドは最終的にjvmレベルのnativeメソッドを呼び出す.jvm実行プラットフォームによっては多少異なる場合があります.オブジェクトがwaitメソッドを呼び出すと、オブジェクトを持つスレッドがオブジェクトの制御権を渡し、待機状態になります.オブジェクトがnotifyメソッドを呼び出すと、そのオブジェクトの制御権を待っているスレッドが実行を続行できることが通知されます.オブジェクトがnotifyAllメソッドを呼び出すと、このオブジェクトの制御権を待つすべてのスレッドが実行を続行することを通知します.
なぜこの3つがThreadクラス宣言の方法ではなく、Objectクラスで宣言する方法なのか疑問に思うかもしれません(もちろんThreadクラスはObjectクラスを継承しているので、Threadは呼び出し者の3つの方法もできます).実はこの問題は簡単です.オブジェクトごとにmonitor(ロック)を持っているので、
だから
現在のスレッドにオブジェクトのロックを待たせるには、もちろんこのオブジェクトで操作する必要があります.現在のスレッドではなく、現在のスレッドが複数のスレッドのロックを待つ可能性があるため、スレッドで操作すると非常に複雑になります.
いずれのオブジェクトにもロック、wait()、notify()、notifyall()メソッドがあります.
現在のスレッドには、このオブジェクトのmonitor(ロック)が必要です.
オブジェクトのwait()メソッドを呼び出す場合、現在のスレッドはそのオブジェクトのmonitor(ロック)を持つ必要があるため、wait()メソッドを呼び出すには同期ブロックまたは同期メソッド(synchronizedブロックまたはsynchronizedメソッド)で行う必要があります.
オブジェクトの制御権はオブジェクトのロックです.
注意:synchroziedメソッドを実行するには、このオブジェクトロックを持つスレッドを使用します.つまり、synchroziedメソッドを実行するには、このオブジェクト制御権を持つスレッドを使用します.さらに、制御権を持ってこそwait()で制御権を解放することができる
 
synchronizedキーワードは、メソッドまたはコードブロックを修飾するために使用される場合、同じ時点で最大1つのスレッドだけがセグメントコードを実行することを保証することができる.
スレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、このobjectのオブジェクトロックが得られる.
スレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、このobjectのオブジェクトロックが得られる.
スレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、このobjectのオブジェクトロックが得られる.
スレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、このobjectのオブジェクトロックが得られる.
四、第三の例は、他の同期コードブロックにも同様に適用される.すなわち、objectのsynchronized(this)同期コードブロックにスレッドがアクセスすると、このobjectのオブジェクトロックが得られる.その結果、objectオブジェクトのすべての同期コード部分への他のスレッドのアクセスが一時的にブロックされる.