Javaにおける同期,非同期,マルチスレッド,マルチスレッド同期,同時,並列に関するいくつかのまとめ
1.同期と非同期
1.1同期
マルチスレッド環境では、複数のスレッドが1つのリソースにアクセスする必要がある場合、ある時点で1つのスレッドしか使用できないリソースをある順序で確保する必要があります.そうしないと、プログラムの実行結果は予測できません.この場合、データを同期する必要があります.例えば、複数のスレッドが同時に同じデータに対して書き込みを行う.すなわち、スレッドAがあるリソースを使用する必要がある場合、このリソースがスレッドBによって使用されている場合、同期メカニズムはスレッドAを待機させ、スレッドBがそのリソースの使用を終了するまでスレッドAがこのリソースを使用することができ、同期メカニズムはリソースの安全を保証することができる.
同期操作を実行するには、各スレッドオブジェクトのロックを取得する必要があります.これを得ることで、同じ時点で1つのスレッドのみが臨界領域(反発リソースにアクセスするコードブロック)に入ることができ、このロックが解放される前に他のスレッドがこの臨界領域に入ることができないことを保証することができる.他のスレッドがオブジェクトのロックを取得する場合は、キューに入って待つしかありません.オブジェクトロックを持つスレッドが臨界領域を終了した場合にのみ解放され、キュー内で最も優先度の高いスレッドがロックを取得して共有コード領域に入るのを待つことができます.
2.マルチスレッド
Javaマルチスレッドを実装する方法
(1)Threadクラスを継承しrun()メソッドを書き換える
Threadは本質的にRunnableインタフェースを実現するインスタンスでもあり、スレッドのインスタンスを表し、スレッドを起動する唯一の方法はThreadクラスのstart()メソッドを通過することである.start()メソッドはローカルメソッドで、新しいスレッドを起動し、run()メソッドを実行します(start()メソッドで呼び出されたrun()メソッドのみが本当に非同期の役割を果たすことができます).**ヒント**start()メソッドが呼び出されると、すぐにマルチスレッドを実行するコードではなく、そのスレッドを実行可能状態にし、いつマルチスレッドコードを実行するかはオペレーティングシステムによって決定されます.(準備完了、運転、保留、終了)
(2)Runnableインタフェースを実現し,run()メソッドを実現する.
ヒント:Threadオブジェクトを作成し、事前にRunnableインタフェースのオブジェクトをパラメータとしてインスタンス化してThreadオブジェクトを変更します.
Callableインタフェースを実現し、call()メソッドを書き換える.(これはポイントではなく使用をお勧めしません)
3.マルチスレッド同期
マルチスレッド同期の方法は何ですか?
(1)synchronizedキーワード
Javaでは、各オブジェクトにはオブジェクトロックが関連付けられています.このロックは、オブジェクトがいつでも1つのスレッドによって所有されることを許可していることを示しています.1つのスレッドがオブジェクトのsynchronizedコードを呼び出すと、まずこのロックを取得し、その後、対応するコードを実行し、実行が終了し、ロックを解放します.
synchronizedキーワードには主に2つの使い方があります.1.synchronized申明方法:public synchronized void xxx();2.synchronizedコードブロック:synchronized(obj){}
(2)wait()メソッドとnotify()メソッド
wait()メソッドは、現在のリソースの占有権を放棄し、誰かが通知するまでオブジェクトロックを解放して待機状態に入ることを示す.notify()メソッドは、現在のスレッドがリソースの占有を放棄したことを示し、待機しているスレッドにリソースの占有権を取得するように通知する.次にwait()の後の文を実行します.起動されたスレッドはwait()でオブジェクトのロックポイントを取得するまでブロックされています:notify()メソッドはリソースの占有を放棄しますが、オブジェクトロックは解放されません.
notify()メソッドとwait()メソッドはsynchronizedキーワードと組み合わせて使用する必要があります.
**“` public class Consumer implements Runnable {
}
public class Produce implements Runnable {
}
テストクラスは次のとおりです.
public class Test {
} “`**
(3)Lock
a.lock():ブロックされた方法でロックを取得します.つまり、ロックを取得すると、すぐに戻ります.他のスレッドがロックを持っている場合、現在のスレッドが待機している場合は、ロックを取得した後に戻ります.
b.tryLock():非ブロックでロックを取得します.ロックを取得しようとするだけで、取得したらtrueを返します.そうしないと、すぐにfalseに戻ります.
c.tryLock(long timeout,TimeUnit unit):ロックを取得した場合、すぐにtrueを返します.そうしないと、パラメータが与えられた時間単位を待機します.待機中、ロックを取得した場合、すぐにtrueを返します.待機がタイムアウトした場合、falseを返します.
d.lockInterruptibly():ロックを取得した場合、すぐに戻ります.そうしないと、現在のスレッドはロックが取得されるまでスリープ状態にあり、または現在のスレッドが他のスレッドによって中断されます.lock()メソッドと最大の違いは、lock()メソッドがロックを取得できない場合、ブロック状態になり、interrupt()メソッドが無視されることです.
**`はwait()とnotify()が連携してスレッド同期を完了するほか,ロックを用いても同様の目的を達成できる.
ReentrantLockはsynchronizedと同じ同時性とメモリの意味を持ち、割り込みロック待機とタイミングロック待機も含まれている.これは、スレッドAがオブジェクトobjのロックを先に取得した場合、スレッドBが所定時間待機してもロックを取得できない場合、自動的にロックを破棄することを意味する.
しかしsynchronizedはJVMレベルで実現されるため、システムはロックの解放の有無を監視することができるが、ReentrantLockはコードで実現され、システムは自動的にロックを解放することができず、コードの中でfinally句の中でロックlock.unlock()を明示的に解放する必要がある.
同じ例でlockを使ってどのように実現しますか?
public class Consumer implements Runnable {
}
public class Producer implements Runnable{
}
呼び出しコード:
public class Test {
}
推奨事項:
コンカレント量が比較的小さい場合はsynchronizedを使用するのが良い選択ですが、コンカレント量が比較的高い場合は性能の低下が深刻で、ReentrantLockは良い案です`**
4.同時並行
同時:単一のプロセッサで、複数のタスクを交互に実行します.複数のタスクが同時に実行されているように見えます.
パラレル:複数のプロセッサで、複数のタスクを同時に実行しますが、各タスクは1つのcpuで実行されます.
1つのイメージの例は、1人の大人が同時に2人の赤ちゃんにご飯をあげ、1人が1口与えるようなものです.並行して2人の大人がそれぞれ2人の赤ちゃんにご飯をあげます.
1.1同期
マルチスレッド環境では、複数のスレッドが1つのリソースにアクセスする必要がある場合、ある時点で1つのスレッドしか使用できないリソースをある順序で確保する必要があります.そうしないと、プログラムの実行結果は予測できません.この場合、データを同期する必要があります.例えば、複数のスレッドが同時に同じデータに対して書き込みを行う.すなわち、スレッドAがあるリソースを使用する必要がある場合、このリソースがスレッドBによって使用されている場合、同期メカニズムはスレッドAを待機させ、スレッドBがそのリソースの使用を終了するまでスレッドAがこのリソースを使用することができ、同期メカニズムはリソースの安全を保証することができる.
同期操作を実行するには、各スレッドオブジェクトのロックを取得する必要があります.これを得ることで、同じ時点で1つのスレッドのみが臨界領域(反発リソースにアクセスするコードブロック)に入ることができ、このロックが解放される前に他のスレッドがこの臨界領域に入ることができないことを保証することができる.他のスレッドがオブジェクトのロックを取得する場合は、キューに入って待つしかありません.オブジェクトロックを持つスレッドが臨界領域を終了した場合にのみ解放され、キュー内で最も優先度の高いスレッドがロックを取得して共有コード領域に入るのを待つことができます.
2.マルチスレッド
Javaマルチスレッドを実装する方法
(1)Threadクラスを継承しrun()メソッドを書き換える
Threadは本質的にRunnableインタフェースを実現するインスタンスでもあり、スレッドのインスタンスを表し、スレッドを起動する唯一の方法はThreadクラスのstart()メソッドを通過することである.start()メソッドはローカルメソッドで、新しいスレッドを起動し、run()メソッドを実行します(start()メソッドで呼び出されたrun()メソッドのみが本当に非同期の役割を果たすことができます).**ヒント**start()メソッドが呼び出されると、すぐにマルチスレッドを実行するコードではなく、そのスレッドを実行可能状態にし、いつマルチスレッドコードを実行するかはオペレーティングシステムによって決定されます.(準備完了、運転、保留、終了)
(2)Runnableインタフェースを実現し,run()メソッドを実現する.
ヒント:Threadオブジェクトを作成し、事前にRunnableインタフェースのオブジェクトをパラメータとしてインスタンス化してThreadオブジェクトを変更します.
Callableインタフェースを実現し、call()メソッドを書き換える.(これはポイントではなく使用をお勧めしません)
3.マルチスレッド同期
マルチスレッド同期の方法は何ですか?
(1)synchronizedキーワード
Javaでは、各オブジェクトにはオブジェクトロックが関連付けられています.このロックは、オブジェクトがいつでも1つのスレッドによって所有されることを許可していることを示しています.1つのスレッドがオブジェクトのsynchronizedコードを呼び出すと、まずこのロックを取得し、その後、対応するコードを実行し、実行が終了し、ロックを解放します.
synchronizedキーワードには主に2つの使い方があります.1.synchronized申明方法:public synchronized void xxx();2.synchronizedコードブロック:synchronized(obj){}
(2)wait()メソッドとnotify()メソッド
wait()メソッドは、現在のリソースの占有権を放棄し、誰かが通知するまでオブジェクトロックを解放して待機状態に入ることを示す.notify()メソッドは、現在のスレッドがリソースの占有を放棄したことを示し、待機しているスレッドにリソースの占有権を取得するように通知する.次にwait()の後の文を実行します.起動されたスレッドはwait()でオブジェクトのロックポイントを取得するまでブロックされています:notify()メソッドはリソースの占有を放棄しますが、オブジェクトロックは解放されません.
notify()メソッドとwait()メソッドはsynchronizedキーワードと組み合わせて使用する必要があります.
**“` public class Consumer implements Runnable {
@Override
public synchronized void run() {
// TODO Auto-generated method stub
int count = 10;
while(count > 0) {
synchronized (Test. obj) {
System. out.print( "B");
count --;
Test. obj.notify(); //
try {
Test. obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class Produce implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
int count = 10;
while(count > 0) {
synchronized (Test. obj) {
//System.out.print("count = " + count);
System. out.print( "A");
count --;
Test. obj.notify();
try {
Test. obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
テストクラスは次のとおりです.
public class Test {
public static final Object obj = new Object();
public static void main(String[] args) {
new Thread( new Produce()).start();
new Thread( new Consumer()).start();
}
} “`**
(3)Lock
a.lock():ブロックされた方法でロックを取得します.つまり、ロックを取得すると、すぐに戻ります.他のスレッドがロックを持っている場合、現在のスレッドが待機している場合は、ロックを取得した後に戻ります.
b.tryLock():非ブロックでロックを取得します.ロックを取得しようとするだけで、取得したらtrueを返します.そうしないと、すぐにfalseに戻ります.
c.tryLock(long timeout,TimeUnit unit):ロックを取得した場合、すぐにtrueを返します.そうしないと、パラメータが与えられた時間単位を待機します.待機中、ロックを取得した場合、すぐにtrueを返します.待機がタイムアウトした場合、falseを返します.
d.lockInterruptibly():ロックを取得した場合、すぐに戻ります.そうしないと、現在のスレッドはロックが取得されるまでスリープ状態にあり、または現在のスレッドが他のスレッドによって中断されます.lock()メソッドと最大の違いは、lock()メソッドがロックを取得できない場合、ブロック状態になり、interrupt()メソッドが無視されることです.
**`はwait()とnotify()が連携してスレッド同期を完了するほか,ロックを用いても同様の目的を達成できる.
ReentrantLockはsynchronizedと同じ同時性とメモリの意味を持ち、割り込みロック待機とタイミングロック待機も含まれている.これは、スレッドAがオブジェクトobjのロックを先に取得した場合、スレッドBが所定時間待機してもロックを取得できない場合、自動的にロックを破棄することを意味する.
しかしsynchronizedはJVMレベルで実現されるため、システムはロックの解放の有無を監視することができるが、ReentrantLockはコードで実現され、システムは自動的にロックを解放することができず、コードの中でfinally句の中でロックlock.unlock()を明示的に解放する必要がある.
同じ例でlockを使ってどのように実現しますか?
public class Consumer implements Runnable {
private Lock lock;
public Consumer(Lock lock) {
this. lock = lock;
}
@Override
public void run() {
// TODO Auto-generated method stub
int count = 10;
while( count > 0 ) {
try {
lock.lock();
count --;
System. out.print( "B");
} finally {
lock.unlock(); //
try {
Thread. sleep(91L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class Producer implements Runnable{
private Lock lock;
public Producer(Lock lock) {
this. lock = lock;
}
@Override
public void run() {
// TODO Auto-generated method stub
int count = 10;
while (count > 0) {
try {
lock.lock();
count --;
System. out.print( "A");
} finally {
lock.unlock();
try {
Thread. sleep(90L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
呼び出しコード:
public class Test {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Consumer consumer = new Consumer(lock);
Producer producer = new Producer(lock);
new Thread(consumer).start();
new Thread( producer).start();
}
}
推奨事項:
コンカレント量が比較的小さい場合はsynchronizedを使用するのが良い選択ですが、コンカレント量が比較的高い場合は性能の低下が深刻で、ReentrantLockは良い案です`**
4.同時並行
同時:単一のプロセッサで、複数のタスクを交互に実行します.複数のタスクが同時に実行されているように見えます.
パラレル:複数のプロセッサで、複数のタスクを同時に実行しますが、各タスクは1つのcpuで実行されます.
1つのイメージの例は、1人の大人が同時に2人の赤ちゃんにご飯をあげ、1人が1口与えるようなものです.並行して2人の大人がそれぞれ2人の赤ちゃんにご飯をあげます.