スレッドの同期と通信
Javaで揮発性、同期して、最終的な可視性を実現。
Javaでは、同期され、ロック、アンロック動作保証の原子を。
Java言語が提供揮発性と同期のスレッド間の秩序ある動作を保証するために、2つのキーワードを
。同期実装スレッド同期
するために複数のスレッドを同期させる同期機構synchonzied 同時に同じリソース・コントロールにアクセスします。
主な目的は、複数のスレッド間で共有するデータの同期を確保することです。同期化は、著しい性能オーバーヘッドをもたらすでしょう、
それは、(むしろオブジェクト全体ロックよりロックに異なるオブジェクトの異なる要素を使用して、)きめの細かい同期であるべきです。
同期が適切に使用されている場合は、パフォーマンス上のオーバーヘッドが無視できる持参。同期本当のリスクは、複雑さとリソースがセキュリティではなく、パフォーマンスを損なう可能性があることです。
ジャワの各オブジェクトが組み込まれているので、ロック、このキーワード修正法を使用した場合、内蔵のロックは、方法全体を保護します。
このメソッドを呼び出す前に、それ以外の場合はブロックされ、内蔵のロックを取得する必要があります。
注意:synchronizedキーワードの静的メソッドも変更することができ、この時点での静的メソッド呼び出した場合、それはクラス全体をロックします。
注:同期は、高コストの操作であるため、同期を最小限にすべきです。
キーコードを使用して、全体の方法同期コードブロックの同期を同期するために通常必要ではありません。
同期方法:同期修飾子はその同期方式にすることができた後、上昇させる方法、
この方法は、静的および非静的メソッドすることができ、
しかし、抽象クラスの抽象メソッドにはできません、またインタフェースのメソッドインタフェースです。
1つの 新しいスレッド(){ 2 @Override 3 公共 ボイドラン(){ 4 同期(本){ 5 のための(int型 I = 'A'; iは= G 'を' <; iは++ ){ 6 System.out.print((CHAR )は、i); 7 } 8 } 9 } 10 } .start();
II。スレッドの同期を実装する揮発性の特殊なドメインの変数を使用します
変数が同期プラス揮発する必要が
アカウント= 100 INTプライベート揮発性、
揮発性のキーワードは、ドメイン変数へのロックフリーアクセスのためのメカニズムを提供
揮発性の修正ドメインを使用してBを別のスレッドの更新をあるかもしれないドメインに仮想マシンを伝えることと等価である。
C.代わりに、レジスタの値を使用してこのようにドメインごとに再計算は、
D. 揮発性動作が任意の原子を提供しないが、それは変数の最終的なタイプ変更するために使用することができない
揮発性変数は、それが有することになる視認性。
揮発性の変数は、スレッドと直接メモリを変更するリオーダバッファ内で許可されていません。
だから、他のスレッドが表示されます。
しかし、揮発性、ここで問題に注意して彼だけが変更され、視認性に満足してみましょう、それがアトミックであることを保証することはできません。
例えば、揮発性のint A = 0; ++動作後、この変数は、可視性を有するが、依然として++非アトミック操作である、
つまり、この操作はまた、スレッド安全性の問題が存在します。
三。スレッドの同期のためのリエントラントロックを使用します
ReentrantLock() : 创建一个ReentrantLock实例
lock() : 获得锁
unlock() : 释放锁
可重入锁
ReentrantLock是可以重入的锁,当一个线程获取锁时,还可以接着重复获取多次。
ReentrantLock需要手动加锁和解锁,且解锁的操作尽量要放在finally代码块中,保证线程正确释放锁。
ReentrantLock和synchronized都是可重入的。
synchronized因为可重入因此可以放在被递归执行的方法上,且不用担心线程最后能否正确释放锁;
ReentrantLock在重入时要却确保重复获取锁的次数必须和重复释放锁的次数一样,否则可能导致其他线程无法获得该锁。
公平锁
是指当锁可用时,在锁上等待时间最长的线程将获得锁的使用权。
而非公平锁则随机分配这种使用权。
和synchronized一样,默认的ReentrantLock实现是非公平锁,因为相比公平锁,非公平锁性能更好。
当然公平锁能防止饥饿,某些情况下也很有用。
在创建ReentrantLock的时候通过传进参数true
创建公平锁,如果传入的是false
或没传参数则创建的是非公平锁
ReentrantLock lock = new ReentrantLock(true);
1 public class ReentrantLockTest { 2 3 public static void main(String[] args) throws InterruptedException { 4 5 ReentrantLock lock = new ReentrantLock(); 6 7 //需要同步的内容在lock()与unlock()之间 8 for (int i = 1; i <= 3; i++) { 9 lock.lock(); 10 } 11 12 for (int i = 1; i <= 3; i++) { 13 try { 14 15 } finally { 16 lock.unlock(); 17 } 18 } 19 } 20 }
四.wait和notify实现线程间通信
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,
调用此方法要捕捉InterruptedException异常。
并不会释放锁
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,
并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
1 /** 2 * 线程交替打印案例 3 * ab1cd2ef3 4 */ 5 //对象锁 6 Object obj = new Object(); 7 new Thread() { 8 @Override 9 public void run() { 10 //同步 11 synchronized (obj) { 12 int a = 2; 13 for (int i = 'a'; i <= 'g'; i++) { 14 if (a == 0) { 15 try { 16 a = 2; 17 //把别人唤醒,自己再睡 18 obj.notifyAll(); 19 obj.wait(); 20 } catch (InterruptedException e) { 21 e.printStackTrace(); 22 } 23 } 24 System.out.print((char) i); 25 a--; 26 } 27 } 28 } 29 }.start(); 30 31 new Thread(new Runnable() { 32 @Override 33 public void run() { 34 synchronized (obj) { 35 for (int i = 1; i <= 10; i++) { 36 System.out.print(i); 37 try { 38 //把别人唤醒,自己再睡 39 obj.notifyAll(); 40 obj.wait(); 41 } catch (InterruptedException e) { 42 e.printStackTrace(); 43 } 44 } 45 } 46 } 47 }).start();