Java同時プログラミングの詳細
カウンタ:CountDownLatch
CountDownLatchは1つのカウンタに似ており、Atomicクラスに近い.動作は原子的である.すなわち、複数のスレッドが同時に1つしか動作できない.CountDownLatchオブジェクトは、カウント値として初期の数値を設定し、このカウンタのカウント値が他のスレッド呼び出しcountDown()によって0に減少するまで、このオブジェクトを呼び出すawait()メソッドはブロックされます.典型的な適用シーンは、次のタスクを実行したい場合ですが、他のタスクが実行されるまで待たなければなりません.例えば、Zookeeperの使用中に、クライアントとサーバとの接続が非同期呼び出しであるため、メインスレッドは、非同期コールバックcountDown()が完了するまでawait()ブロックする必要がある.
コードの例:
歩調をそろえる:CyclicBarrier
Barrierはフェンスを意味し、すべてのスレッドが揃うまでスレッドのセットを互いに待たせることで、歩調をそろえることができます.Cyclicはサイクルという意味で、Barrierはリサイクルできるということです.CyclicBarrierの主な方法はawait()であり,CountDownLatchのawait()よりもブロックされているが,CyclicBarrier.await()には戻り値intがあり,すなわち現在のスレッドがこのBarrierに到達する数番目のスレッドである.
CyclicBarrierを構築するときにカウント値を指定し、await()メソッドが呼び出されるたびにカウントが1減少し、現在のスレッドがブロックされます.カウントが0に減少すると、ブロックが解除され、CyclicBarrier上でブロックされたすべてのスレッドが実行されます.その後、await()メソッドを再び呼び出すと、カウントはN-1になり、新しいラウンドが再開されます.構築方法ではRunnableオブジェクトを渡すこともでき、ブロック解除時にこのRunnableが実行されます.
CyclicBarrierは少し「会わないと散らない」味がしますが、もしあるメンバーが何らかの理由でBarrierという場所に来られなかったら、私たちはずっと待っていますか?実際、来られなければ他のメンバーに知らせるべきで、待たないで、家に帰りましょう.CyclicBarrier.await()独自のBrokenBarrierException異常に注意
コードの例:
Callable And Future
ブロガーの以前のブログ「Java Futureモード実装」ではFutureモードが紹介されていましたが、Futureモードは処理に時間がかかるビジネスロジックに適しており、システムの応答時間を効果的に削減し、システムのスループットを向上させることができます.JDKはすでにAPI実装を提供しています.コードを見てみましょう.
スレッドプールでタスクを実行するには、次の2つの方法があります.
submitとexecuteの違いは何ですか?入参と結果タイプからわかります.
信号量:Semaphore
Semaphoreが実現した機能はトイレに5つの穴があるのと似ており、10人がトイレに行くと明らかに同時に5人しかトイレを占有できず、5人のいずれかが譲った後、待機していた他の5人のうち1人が占有できるようになった.また、待機している5人の中では、Semaphoreオブジェクトを構築する際に入力されるfairパラメータオプションに応じて、ランダムに優先順位を獲得してもよいし、先着順に機会を獲得してもよい.
Semaphoreは、あるリソースが同時にアクセスできる個数(構築方法が入力される)を制御し、acquire()によってライセンスを取得し、なければ待機し、release()によってライセンスを解放することができる.
コードの例:
CountDownLatchは1つのカウンタに似ており、Atomicクラスに近い.動作は原子的である.すなわち、複数のスレッドが同時に1つしか動作できない.CountDownLatchオブジェクトは、カウント値として初期の数値を設定し、このカウンタのカウント値が他のスレッド呼び出しcountDown()によって0に減少するまで、このオブジェクトを呼び出すawait()メソッドはブロックされます.典型的な適用シーンは、次のタスクを実行したい場合ですが、他のタスクが実行されるまで待たなければなりません.例えば、Zookeeperの使用中に、クライアントとサーバとの接続が非同期呼び出しであるため、メインスレッドは、非同期コールバックcountDown()が完了するまでawait()ブロックする必要がある.
コードの例:
public class CountDownLatchTest {
public static void main(String[] args) {
final CountDownLatch countDownLatch = new CountDownLatch(2);
Thread work1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread() + " doing work...start");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + " doing work...end ");
countDownLatch.countDown();
}
},"work1");
Thread work2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " doing work...start");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " doing work...end ");
countDownLatch.countDown();
}
},"work2");
work1.start();
work2.start();
try {
countDownLatch.await();
System.out.println("all workers finish ");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
歩調をそろえる:CyclicBarrier
Barrierはフェンスを意味し、すべてのスレッドが揃うまでスレッドのセットを互いに待たせることで、歩調をそろえることができます.Cyclicはサイクルという意味で、Barrierはリサイクルできるということです.CyclicBarrierの主な方法はawait()であり,CountDownLatchのawait()よりもブロックされているが,CyclicBarrier.await()には戻り値intがあり,すなわち現在のスレッドがこのBarrierに到達する数番目のスレッドである.
CyclicBarrierを構築するときにカウント値を指定し、await()メソッドが呼び出されるたびにカウントが1減少し、現在のスレッドがブロックされます.カウントが0に減少すると、ブロックが解除され、CyclicBarrier上でブロックされたすべてのスレッドが実行されます.その後、await()メソッドを再び呼び出すと、カウントはN-1になり、新しいラウンドが再開されます.構築方法ではRunnableオブジェクトを渡すこともでき、ブロック解除時にこのRunnableが実行されます.
CyclicBarrierは少し「会わないと散らない」味がしますが、もしあるメンバーが何らかの理由でBarrierという場所に来られなかったら、私たちはずっと待っていますか?実際、来られなければ他のメンバーに知らせるべきで、待たないで、家に帰りましょう.CyclicBarrier.await()独自のBrokenBarrierException異常に注意
コードの例:
public class CyclicBarrierTest {
public static void main(String[] args) {
final CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
System.out.println(" !");
}
});
Thread runman1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + "i am ok");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
},"runman1");
Thread runman2 = new Thread(new Runnable() {
@Override
public void run() {
try {
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + "i am ok");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
},"runman2");
runman1.start();
runman2.start();
}
}
Callable And Future
ブロガーの以前のブログ「Java Futureモード実装」ではFutureモードが紹介されていましたが、Futureモードは処理に時間がかかるビジネスロジックに適しており、システムの応答時間を効果的に削減し、システムのスループットを向上させることができます.JDKはすでにAPI実装を提供しています.コードを見てみましょう.
public class FutureTest {
public static void main(String[] args) {
FutureTask futureTask = new FutureTask(new Callable() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "ok";
}
});
ExecutorService es = Executors.newFixedThreadPool(1);
es.submit(futureTask);
System.out.println(" , !");
try {
System.out.println(" :" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
スレッドプールでタスクを実行するには、次の2つの方法があります.
submitとexecuteの違いは何ですか?入参と結果タイプからわかります.
信号量:Semaphore
Semaphoreが実現した機能はトイレに5つの穴があるのと似ており、10人がトイレに行くと明らかに同時に5人しかトイレを占有できず、5人のいずれかが譲った後、待機していた他の5人のうち1人が占有できるようになった.また、待機している5人の中では、Semaphoreオブジェクトを構築する際に入力されるfairパラメータオプションに応じて、ランダムに優先順位を獲得してもよいし、先着順に機会を獲得してもよい.
Semaphoreは、あるリソースが同時にアクセスできる個数(構築方法が入力される)を制御し、acquire()によってライセンスを取得し、なければ待機し、release()によってライセンスを解放することができる.
コードの例:
public static void main(String[] args) {
final Semaphore semaphore = new Semaphore(5);
for(int i = 0 ; i
Condition
JDK synchronized Lock, , 、 , , tryLock 。 synchronized wait/notify/notifyAll , JDK , Condition。Condition.await wait,Condition.signal/signalAll notify/nofityAll。 Condition / 。
:Handler
public class Handler {
//
private LinkedList linkedList = new LinkedList();
//
private int MAX_SIZE = 3;
//
private Lock lock = new ReentrantLock();
//condition , new condition,
private Condition condition = lock.newCondition();
public void put(String bread){
try{
lock.lock();
if(linkedList.size() == MAX_SIZE){
System.out.println(" ");
condition.await();
}
linkedList.add(bread);
System.out.println(" " + bread);
condition.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void eat(){
try{
lock.lock();
if(linkedList.size() == 0){
System.out.println(" ");
condition.await();
}
String bread = linkedList.removeFirst();
System.out.println(" " + bread);
condition.signalAll();
}catch(Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
:Producepublic class Produce implements Runnable{
private Handler handler;
public Produce(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
for(int i = 0 ; i
:Consume
public class Consume implements Runnable{
private Handler handler;
public Consume(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
for (int i = 0 ; i
Main:
public class Main {
public static void main(String[] args) {
Handler handler = new Handler();
Produce produce = new Produce(handler);
Consume consume = new Consume(handler);
new Thread(consume).start();
new Thread(produce).start();
new Thread(produce).start();
}
}