JAvaスレッドの通信とスレッドプール
3681 ワード
1.従来のスレッド通信
synchronized修飾の同期メソッドまたは同期コードブロックを使用すると、wait()、notify()、notifyAll()の3つのメソッドがメソッド体重で直接呼び出されます.次のようになります.
wait():現在のスレッドを待機させ、他のスレッドが同期モニタを呼び出すnotify()またはnotifyAll()メソッドを知る.
notify():この同期モニタで待機している単一のスレッドを起動します.
notifyAll():この同期モニタで待機しているすべてのスレッドを起動します.
2.Condition制御スレッドによる通信
プログラムでsynchronizedキーワードを用いて同期を実現しない場合,ロックオブジェクトを直接用いて同期を保証する場合,上記3つの方法は使用できない.ロックオブジェクトのnewCondition()メソッドで返されるConditionインスタンスを使用して、同期通信を制御するのが一般的です.すなわち,Conditionクラスのawait(),signal(),signalAll()メソッドを用いて,上述した3つのメソッドをそれぞれ代替する.
3.ブロックキューを使用してスレッド通信を制御する
BlockingQueueはQueueのサブインタフェースですが、あるスレッドがBloockingQueueに要素を入れようとすると、キューがいっぱいになるとスレッドがブロックされ、逆にあるスレッドがキューから要素を取り、キューが空になるとスレッドもブロックされます.次のようになります.
システムが新しいスレッドを起動するコストが高いため、スレッドプールを使用すると、システムの起動時に大量の空きスレッドを作成でき、スレッドプールはシステムで同時に実行されるスレッドの数を効果的に制御し、システムの効率的な性能を維持することができます.使用方法は次のとおりです.
スレッドプールを使用して、複数の分解タスクを計算します.
synchronized修飾の同期メソッドまたは同期コードブロックを使用すると、wait()、notify()、notifyAll()の3つのメソッドがメソッド体重で直接呼び出されます.次のようになります.
wait():現在のスレッドを待機させ、他のスレッドが同期モニタを呼び出すnotify()またはnotifyAll()メソッドを知る.
notify():この同期モニタで待機している単一のスレッドを起動します.
notifyAll():この同期モニタで待機しているすべてのスレッドを起動します.
2.Condition制御スレッドによる通信
プログラムでsynchronizedキーワードを用いて同期を実現しない場合,ロックオブジェクトを直接用いて同期を保証する場合,上記3つの方法は使用できない.ロックオブジェクトのnewCondition()メソッドで返されるConditionインスタンスを使用して、同期通信を制御するのが一般的です.すなわち,Conditionクラスのawait(),signal(),signalAll()メソッドを用いて,上述した3つのメソッドをそれぞれ代替する.
3.ブロックキューを使用してスレッド通信を制御する
BlockingQueueはQueueのサブインタフェースですが、あるスレッドがBloockingQueueに要素を入れようとすると、キューがいっぱいになるとスレッドがブロックされ、逆にあるスレッドがキューから要素を取り、キューが空になるとスレッドもブロックされます.次のようになります.
import java.util.concurrent.*;
class Producer extends Thread
{
private BlockingQueue bq;
public Producer(BlockingQueue bq)
{
this.bq=bq;
}
@Override
public void run()
{
String[] strArr=new String[]{"Java"," ","Spring"};
for(int i=0;i<33333;i++)
{
System.out.println(getName()+" ");
try
{
Thread.sleep(200);
bq.put(strArr[i%3]);
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println(getName()+" :"+bq);
}
}
}
class Consumer extends Thread
{
private BlockingQueue bq;
public Consumer(BlockingQueue bq)
{
this.bq=bq;
}
@Override
public void run()
{
while(true)
{
System.out.println(getName()+" !");
try
{
Thread.sleep(200);
bq.take();
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println(getName()+" :"+bq);
}
}
}
public class BlockingQueueTest2
{
public static void main(String[] args)
{//
// 1
BlockingQueue bq=new ArrayBlockingQueue<>(1);
// 3 1
new Producer(bq).start();
new Producer(bq).start();
new Producer(bq).start();
new Consumer(bq).start();
}
}
4.スレッドプールシステムが新しいスレッドを起動するコストが高いため、スレッドプールを使用すると、システムの起動時に大量の空きスレッドを作成でき、スレッドプールはシステムで同時に実行されるスレッドの数を効果的に制御し、システムの効率的な性能を維持することができます.使用方法は次のとおりです.
import java.util.concurrent.*;
class MyThread implements Runnable
{// Runnable
public void run()
{
for(int i=0;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+"i :"+i);
}
}
public static void main(String[] args)
{
//
ExecutorService pool=Executors.newFixedThreadPool(6);
// 2
pool.submit(new MyThread());
pool.submit(new MyThread());
pool.shutdown();//
}
}
スレッドプールを使用して、複数の分解タスクを計算します.
import java.util.concurrent.*;
import java.util.*;
class CalTask extends RecursiveTask
{//
// 20
private static final int THREADHOLD=20;
private int arr[];//
private int start;//
private int end;//
public CalTask(int[] arr,int start,int end)
{
this.arr=arr;
this.start=start;
this.end=end;
}
@Override
protected Integer compute()
{//
int sum=0;
if(end-start future=pool.submit(new CalTask(arr,0,arr.length));
//
System.out.println(future.get());
pool.shutdown();
}
}