4.共有モデルの管理

この章の内容

  • 問題の共有
  • 同期
  • スレッドセーフ分析
  • モニター
  • 待つ/通知する
  • スレッドの状態遷移
  • 活発さ
  • ロック
     

待機/通知の原則

  • 所有者スレッドは、条件が満たされていないことを検出し、waitメソッドを呼び出してWaitSet状態に入り、WAITING状態に変更します。
  • BLOCKEDスレッドとWAITINGスレッドはブロックされた状態にあり、CPUタイムスライスを占有しません
  • 所有者スレッドがロックを解除すると、BLOCKEDスレッドがウェイクアップします
  • 所有者スレッドがnotifyまたはnotifyAllを呼び出すと、WAITINGスレッドがウェイクアップしますが、ウェイクアップはロックがすぐに取得されることを意味するわけではなく、再度競合するにはEntryListに入る必要があります。

APIの紹介

obj.wait()オブジェクトモニターに入るスレッドが
waitSetを待機しているオブジェクトでobj.notify()を待機するようにし、オブジェクトwaitSetを待機しているスレッドの1つを選択して
obj.notifyAll()をウェイクアップしますオブジェクトでwaitSetを待機しているすべてのスレッドをウェイクアップさせます

これらはすべてスレッド間のコラボレーションの手段であり、すべてObjectオブジェクトのメソッドです。これらのメソッドを呼び出す前に、このオブジェクトのロックを取得する必要があります

final static Object obj = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (obj) {
log.debug("执行....");
try {
obj.wait(); // 让线程在obj上一直等待下去
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("其它代码....");
}
}).start();
new Thread(() -> {
synchronized (obj) {
log.debug("执行....");
try {
obj.wait(); // 让线程在obj上一直等待下去
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("其它代码....");
}
}).start();
// 主线程两秒后执行
sleep(2);
log.debug("唤醒 obj 上其它线程");
synchronized (obj) {
obj.notify(); // 唤醒obj上一个线程
// obj.notifyAll(); // 唤醒obj上所有等待线程
}
}

通知の結果

20:00:53.096 [Thread-0] c.TestWaitNotify - 执行....
20:00:53.099 [Thread-1] c.TestWaitNotify - 执行....
20:00:55.096 [main] c.TestWaitNotify - 唤醒 obj 上其它线程
20:00:55.096 [Thread-0] c.TestWaitNotify - 其它代码....

notifyAllの結果

19:58:15.457 [Thread-0] c.TestWaitNotify - 执行....
19:58:15.460 [Thread-1] c.TestWaitNotify - 执行....
19:58:17.456 [main] c.TestWaitNotify - 唤醒 obj 上其它线程
19:58:17.456 [Thread-1] c.TestWaitNotify - 其它代码....
19:58:17.456 [Thread-0] c.TestWaitNotify - 其它代码....

wait()メソッドは、オブジェクトのロックを解放してWaitSet待機領域に入るので、他のスレッドはオブジェクトのロックを取得する機会があります。
通知までの無制限の待機
wait(long n)時間制限のある待機、nミリ秒後まで待機、または通知される

4.8待機通知の正しい姿勢

始める前に見てください

sleep(long n)とwait(long n)の違い
1)sleepはThreadメソッドであり、waitはObjectメソッドです。2)sleepは同期と組み合わせて使用​​する必要はありませんが、waitは同期と組み合わせて使用​​する必要があります。 3)スリープはスリープ中です同時に、オブジェクトロックは解放されませんが、待機すると、待機中にオブジェクトロックが解放されます。4)ステータスはTIMED_WAITINGです。

synchronized(lock) {
while(条件不成立) {
lock.wait();
}
// 干活
}
//另一个线程
synchronized(lock) {
lock.notifyAll();
}

4.9パーク&アンパーク

基本的な使い方

LockSupportクラスのメソッドです

// 暂停当前线程
LockSupport.park();
// 恢复某个线程的运行
LockSupport.unpark(暂停线程对象)

最初に駐車してから駐車を解除します

Thread t1 = new Thread(() -> {
log.debug("start...");
sleep(1);
log.debug("park...");
LockSupport.park();
log.debug("resume...");
},"t1");
t1.start();
sleep(2);
log.debug("unpark...");
LockSupport.unpark(t1);

出力

18:42:52.585 c.TestParkUnpark [t1] - start...
18:42:53.589 c.TestParkUnpark [t1] - park...
18:42:54.583 c.TestParkUnpark [main] - unpark...
18:42:54.583 c.TestParkUnpark [t1] - resume...

最初に駐車を解除してから駐車します

Thread t1 = new Thread(() -> {
log.debug("start...");
sleep(2);
log.debug("park...");
LockSupport.park();
log.debug("resume...");
}, "t1");
t1.start();
sleep(1);
log.debug("unpark...");
LockSupport.unpark(t1);

出力

18:43:50.765 c.TestParkUnpark [t1] - start...
18:43:51.764 c.TestParkUnpark [main] - unpark...
18:43:52.769 c.TestParkUnpark [t1] - park...
18:43:52.769 c.TestParkUnpark [t1] - resume...

特徴

オブジェクトの待機と通知と比較

  • 待機、通知、notifyAllはオブジェクトモニターと一緒に使用する必要がありますが、パークとアンパークは使用する必要はありません。
  • park&unparkはスレッドをユニットとして使用してスレッドを[ブロック]および[ウェイクアップ]しますが、notifyは1つの待機中のスレッドのみをランダムにウェイクアップできますが、notifyAllはすべての待機中のスレッドをウェイクアップします。
  • park&unparkは最初にパークを解除できますが、wait&notifyは最初に通知できません

パーク&アンパークの原則

各スレッドには、_counter、_cond、_mutexの3つの部分で構成される独自のParkerオブジェクトがあります。比喩を作るために、
スレッドは旅行者のようなものであり、Parkerは彼が携行するバックパックのようなものです。条件変数はテントのようなものです。バックパックで。_counterは
バックパックの予備のドライフードのようなものです(0が使い果たされ、1で十分です)。
パークの呼び出しは、停止して休む必要があるかどうかによって異なります。
スペアのドライフードが使い果たされた
場合は、テントに入れて休憩します。予備乾燥食品は、あなたが滞在する必要はありません、十分である。行くください。
unparkを呼び出し、十分な乾燥食品を作るようなものです。
スレッドがこの時点で10トンにまだある場合は、それを覚ますと、彼が上に移動しましょう。
もしスレッドはこの時点でまだ実行されています。次にパークに電話をかけると、予備のドライフードのみが消費され、滞在する必要はありません。続行します。
バックパックのスペースが限られているため、パーク解除を複数回呼び出すとスペアが追加されるだけです。乾燥食品。

1.現在のスレッドがUnsafe.park()メソッドを呼び出します
2. _counterを確認します。この状況は0です。この時点で、_mutexミューテックスを取得します。3
。スレッドは_cond条件変数ブロッキングに入ります
。4。_counter= 0を設定します。

1. Unsafe.unpark(Thread_0)メソッドを呼び出し、_counterを1に設定します。2。_cond
の条件変数でThread_0をウェイクアップします。3。Thread_0で
操作を再開します
。4。_counterを0に設定します。

1. Unsafe.unpark(Thread_0)メソッドを呼び出し、_counterを1に設定します
。2。現在のスレッドがUnsafe.park()メソッドを呼び出します。3。_counterを
確認します。この状況は1であるため、スレッドは必要ありません。ブロックされ、実行を継続します4。Set_counter
は0です。

4.10スレッドの状態遷移を再理解する

 

4.11複数のロック

複数の無関係なロック

大きな部屋には、睡眠と勉強という2つの機能がありますが、これらは互いに関連していません。
今シャオナンは勉強したいと少女はスリープ状態に望んでいるが、唯一の1部屋(1オブジェクトロック)が使用されている場合、同時性は非常に低いです。
解決策は、複数の部屋(複数のオブジェクトのロックを)準備することです。
たとえば、

class BigRoom {
public void sleep() {
synchronized (this) {
log.debug("sleeping 2 小时");
Sleeper.sleep(2);
}
}
public void study() {
synchronized (this) {
log.debug("study 1 小时");
Sleeper.sleep(1);
}
}
}

実施した

BigRoom bigRoom = new BigRoom();
new Thread(() -> {
bigRoom.compute();
},"小南").start();
new Thread(() -> {
bigRoom.sleep();
},"小女").start();

ある結果

12:13:54.471 [小南] c.BigRoom-1時間勉強12:13:55.476 [小
女] c.BigRoom-2時間寝る

改善する

class BigRoom {
private final Object studyRoom = new Object();
private final Object bedRoom = new Object();
public void sleep() {
synchronized (bedRoom) {
log.debug("sleeping 2 小时");
Sleeper.sleep(2);
}
}
public void study() {
synchronized (studyRoom) {
log.debug("study 1 小时");
Sleeper.sleep(1);
}
}
}

特定の実行の結果

12:15:35.069 [小南] c.BigRoom-1時間勉強12:15:35.069 [小
女] c.BigRoom-2時間寝る

ロックの粒度を分解します

  • 利点は、並行性を強化できることです
  • 欠点、スレッドが同時に複数のロックを取得する必要がある場合、デッドロックが発生しやすくなります

4.12活気

デッドロック

スレッドが同時に複数のロックを取得する必要があり、この時点でデッドロックが発生しやすい状況があります
。t1スレッドはオブジェクトAのロックを取得してから、オブジェクトBのロックを取得したいと考えています。t2スレッドは取得します。オブジェクトBのロック、次にAロックケースのオブジェクトを取得したい

Object A = new Object();
Object B = new Object();
Thread t1 = new Thread(() -> {
synchronized (A) {
log.debug("lock A");
sleep(1);
synchronized (B) {
log.debug("lock B");
log.debug("操作...");
}
}
}, "t1");
Thread t2 = new Thread(() -> {
synchronized (B) {
log.debug("lock B");
sleep(0.5);
synchronized (A) {
log.debug("lock A");
log.debug("操作...");
}
}
}, "t2");
t1.start();
t2.start();

結果

12:22:06.962 [t2] c.TestDeadLock-ロックB12
:22:06.962 [t1] c.TestDeadLock-ロックA

哲学者の食事の問題

円卓の周りには5人の哲学者が座っています。

  • 彼らは、考えることと食べること、しばらく食べることを考えること、そして食べた後に考えることの2つのことだけをします。
  • 食事には2本の箸を使います。テーブルには5本の箸があります。各哲学者は左右に1本の箸を持っています。
  • 周りの人が箸を持っていると待たなければなりません

class Chopstick {
String name;
public Chopstick(String name) {
this.name = name;
}
@Override
public String toString() {
return "筷子{" + name + '}';
}
}

哲学者

class Philosopher extends Thread {
Chopstick left;
Chopstick right;
public Philosopher(String name, Chopstick left, Chopstick right) {
super(name);
this.left = left;
this.right = right;
}
private void eat() {
log.debug("eating...");
Sleeper.sleep(1);
}
@Override
public void run() {
while (true) {
// 获得左手筷子
synchronized (left) {
// 获得右手筷子
synchronized (right) {
// 吃饭
eat();
}
// 放下右手筷子
}
// 放下左手筷子
}
}
}

ダイニング

Chopstick c1 = new Chopstick("1");
Chopstick c2 = new Chopstick("2");
Chopstick c3 = new Chopstick("3");
Chopstick c4 = new Chopstick("4");
Chopstick c5 = new Chopstick("5");
new Philosopher("苏格拉底", c1, c2).start();
new Philosopher("柏拉图", c2, c3).start();
new Philosopher("亚里士多德", c3, c4).start();
new Philosopher("赫拉克利特", c4, c5).start();
new Philosopher("阿基米德", c5, c1).start();

しばらくすると、継続しなくなります。

12:33:15.575 [ソクラテス] c。哲学者を食べる...
12:33:15.575 [アリストテレス] c。哲学者を食べる...
12:33:16.580 [アルキメデス] c。哲学者を食べる...
12: 33:17.580 [アルキメデス] c。哲学者を食べる...
//ここで立ち往生している

jconsoleを使用してデッドロックを検出し、

-------------------------------------------------------------------------
名称: 阿基米德
状态: cn.itcast.Chopstick@1540e19d (筷子1) 上的BLOCKED, 拥有者: 苏格拉底
总阻止数: 2, 总等待数: 1
堆栈跟踪:
cn.itcast.Philosopher.run(TestDinner.java:48)
- 已锁定 cn.itcast.Chopstick@6d6f6e28 (筷子5)
-------------------------------------------------------------------------
名称: 苏格拉底
状态: cn.itcast.Chopstick@677327b6 (筷子2) 上的BLOCKED, 拥有者: 柏拉图
总阻止数: 2, 总等待数: 1
堆栈跟踪:
cn.itcast.Philosopher.run(TestDinner.java:48)
- 已锁定 cn.itcast.Chopstick@1540e19d (筷子1)
-------------------------------------------------------------------------
名称: 柏拉图
状态: cn.itcast.Chopstick@14ae5a5 (筷子3) 上的BLOCKED, 拥有者: 亚里士多德
总阻止数: 2, 总等待数: 0
堆栈跟踪:
cn.itcast.Philosopher.run(TestDinner.java:48)
- 已锁定 cn.itcast.Chopstick@677327b6 (筷子2)
-------------------------------------------------------------------------
名称: 亚里士多德
状态: cn.itcast.Chopstick@7f31245a (筷子4) 上的BLOCKED, 拥有者: 赫拉克利特
总阻止数: 1, 总等待数: 1
堆栈跟踪:
cn.itcast.Philosopher.run(TestDinner.java:48)
- 已锁定 cn.itcast.Chopstick@14ae5a5 (筷子3)
-------------------------------------------------------------------------
名称: 赫拉克利特
状态: cn.itcast.Chopstick@6d6f6e28 (筷子5) 上的BLOCKED, 拥有者: 阿基米德
总阻止数: 2, 总等待数: 0
堆栈跟踪:
cn.itcast.Philosopher.run(TestDinner.java:48)
- 已锁定 cn.itcast.Chopstick@7f31245a (筷子4)发现

この種のスレッドは期待どおりに終了せず、実行を続行できず、[活性]問題に分類されます。デッドロックに加えて、ライブロックと空腹の2つのケースがあります。

Livelock

たとえば、2つのスレッドが互いの終了条件を変更し、誰も終了できない場合、ライブロックが発生します。

public class TestLiveLock {
static volatile int count = 10;
static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
// 期望减到 0 退出循环
while (count > 0) {
sleep(0.2);
count--;
log.debug("count: {}", count);
}
}, "t1").start();
new Thread(() -> {
// 期望超过 20 退出循环
while (count < 20) {
sleep(0.2);
count++;
log.debug("count: {}", count);
}
}, "t2").start();
}
}

飢え

多くのチュートリアルでは、空腹は優先度が低すぎるため、CPUによってスケジュールおよび実行できず、終了できないため、スレッドとして定義されます。空腹の状況を示すのは簡単ではありません。読み取り/書き込みロックについて話すとき、空腹の問題が発生します。
私の遭遇について話しましょう。スレッドの枯渇の例として、前のデッドロックの問題を解決するためのシーケンシャルロックの使用を見てみましょう。

シーケンシャルロックソリューション

4.13 ReentrantLock

同期と比較すると、次の特性があります。
割り込み可能
タイムアウト
を設定できる、フェアロック、
複数の条件変数、
同期、どちらも再入可能
な基本構文をサポートします

// 获取锁
reentrantLock.lock();
try {
// 临界区
} finally {
// 释放锁
reentrantLock.unlock();
}

リエントラント


再入可能とは、同じスレッドが初めてロックを取得した場合、そのスレッドがロックの所有者であるため、再度ロックを取得する権利があることを意味します。再入可能でないロックの場合は、ロックが取得されたときに二度目、私はロックによってブロックされます

static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
method1();
}
public static void method1() {
lock.lock();
try {
log.debug("execute method1");
method2();
} finally {
lock.unlock();
}
}
public static void method2() {
lock.lock();
try {
log.debug("execute method2");
method3();
} finally {
lock.unlock();
}
}
public static void method3() {
lock.lock();
try {
log.debug("execute method3");
} finally {
lock.unlock();
}
}

出力

17:59:11.862 [main] c.TestReentrant - execute method1
17:59:11.865 [main] c.TestReentrant - execute method2
17:59:11.865 [main] c.TestReentrant - execute method3

中断することができます

ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug("启动...");
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
log.debug("等锁的过程中被打断");
return;
}
try {
log.debug("获得了锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
log.debug("获得了锁");
t1.start();
try {
sleep(1);
t1.interrupt();
log.debug("执行打断");
} finally {
lock.unlock();
}

出力

18:02:40.520 [main] c.TestInterrupt - 获得了锁
18:02:40.524 [t1] c.TestInterrupt - 启动...
18:02:41.530 [main] c.TestInterrupt - 执行打断
java.lang.InterruptedException
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchr
onizer.java:898)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchron
izer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at cn.itcast.n4.reentrant.TestInterrupt.lambda$main$0(TestInterrupt.java:17)
at java.lang.Thread.run(Thread.java:748)
18:02:41.532 [t1] c.TestInterrupt - 等锁的过程中被打断

割り込み不可能モードの場合、割り込みを使用しても待機は中断されないことに注意してください。

ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug("启动...");
lock.lock();
try {
log.debug("获得了锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
log.debug("获得了锁");
t1.start();
try {
sleep(1);
t1.interrupt();
log.debug("执行打断");
sleep(1);
} finally {
log.debug("释放了锁");
lock.unlock();
}

出力

18:06:56.261 [main] c.TestInterrupt - 获得了锁
18:06:56.265 [t1] c.TestInterrupt - 启动...
18:06:57.266 [main] c.TestInterrupt - 执行打断 // 这时 t1 并没有被真正打断, 而是仍继续等待锁
18:06:58.267 [main] c.TestInterrupt - 释放了锁
18:06:58.267 [t1] c.TestInterrupt - 获得了锁

ロックタイムアウト

すぐに失敗する

ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug("启动...");
if (!lock.tryLock()) {
log.debug("获取立刻失败,返回");
return;
}
try {
log.debug("获得了锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
log.debug("获得了锁")
t1.start();
try {
sleep(2);
} finally {
lock.unlock();
}

出力

18:15:02.918 [main] c.TestTimeout-ロックを取得しました
18:15:02.921 [t1] c.TestTimeout-開始...
18:15:02.921 [t1] c.TestTimeout-すぐに取得できず、戻りに失敗しました
タイムアウト
 

ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug("启动...");
try {
if (!lock.tryLock(1, TimeUnit.SECONDS)) {
log.debug("获取等待 1s 后失败,返回");
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
log.debug("获得了锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
log.debug("获得了锁");
t1.start();
try {
sleep(2);
} finally {
lock.unlock();
}

出力

18:19:40.537 [main] c.TestTimeout - 获得了锁
18:19:40.544 [t1] c.TestTimeout - 启动...
18:19:41.547 [t1] c.TestTimeout - 获取等待 1s 后失败,返回

tryLockを使用して、哲学者の食事する問題を解決します
 

class Chopstick extends ReentrantLock {
String name;
public Chopstick(String name) {
this.name = name;
}
@Override
public String toString() {
return "筷子{" + name + '}';
}
}

 

class Philosopher extends Thread {
Chopstick left;
Chopstick right;
public Philosopher(String name, Chopstick left, Chopstick right) {
super(name);
this.left = left;
this.right = right;
}
@Override
public void run() {
while (true) {
// 尝试获得左手筷子
if (left.tryLock()) {
try {
// 尝试获得右手筷子
if (right.tryLock()) {
try {
eat();
} finally {
right.unlock();
}
}
} finally {
left.unlock();
}
}
}
}
private void eat() {
log.debug("eating...");
Sleeper.sleep(1);
}
}

フェアロック

ReentrantLockはデフォルトで不公平です

ReentrantLock lock = new ReentrantLock(false);
lock.lock();
for (int i = 0; i < 500; i++) {
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " running...");
} finally {
lock.unlock();
}
}, "t" + i).start();
}
// 1s 之后去争抢锁
Thread.sleep(1000);
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " start...");
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " running...");
} finally {
lock.unlock();
}
}, "强行插入").start();
lock.unlock();

強制挿入、途中で出力する可能性があります
注:この実験は必ずしも再現できるとは限りません

条件変数

同期には条件変数もあります。これは、原則について説明するときのwaitSetラウンジです。条件が満たされない場合は、waitSetに入り、
ReentrantLockを待ちます。条件変数は、複数の条件変数をサポートするという点で、同期よりも強力です。のようなものです

  • 同期されているのは、条件を満たさないスレッドがラウンジでニュースを待っているということです。
  • また、ReentrantLockは複数のラウンジをサポートしており、タバコを待つための専用ラウンジ、朝食を待つための専用ラウンジ、目覚めたときにラウンジのそばで目を覚ますことができます。

主な使用ポイント:

  • 待つ前にロックを取得する必要があります
  • awaitが実行された後、ロックが解除され、conditionObjectを入力して待機します
  • 待機スレッドが起動(または中断、またはタイムアウト)されて、ロックロックを再競合します
  • 競合ロックが正常にロックされたら、待機後に実行を続行します

例:

static ReentrantLock lock = new ReentrantLock();
static Condition waitCigaretteQueue = lock.newCondition();
static Condition waitbreakfastQueue = lock.newCondition();
static volatile boolean hasCigrette = false;
static volatile boolean hasBreakfast = false;
public static void main(String[] args) {
new Thread(() -> {
try {
lock.lock();
while (!hasCigrette) {
try {
waitCigaretteQueue.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("等到了它的烟");
} finally {
lock.unlock();
}
}).start();
new Thread(() -> {
try {
lock.lock();
while (!hasBreakfast) {
try {
waitbreakfastQueue.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("等到了它的早餐");
} finally {
lock.unlock();
}
}).start();
sleep(1);
sendBreakfast();
sleep(1);
sendCigarette();
}
private static void sendCigarette() {
lock.lock();
try {
log.debug("送烟来了");
hasCigrette = true;
waitCigaretteQueue.signal();
} finally {
lock.unlock();
}
}
private static void sendBreakfast() {
lock.lock();
try {
log.debug("送早餐来了");
hasBreakfast = true;
waitbreakfastQueue.signal();
} finally {
lock.unlock();
}
}

出力

18:52:27.680 [main] c.TestCondition-朝食の配達
18:52:27.682 [Thread-1] c.TestCondition-朝食を待っていた
18:52:28.683 [main] c.TestCondition-煙の配達
18 :52:28.683 [スレッド-0] c.TestCondition-それまで煙を出す

章のまとめ

この章で焦点を当てる必要があるのは

  • 共有リソースへのマルチスレッドアクセス時に、どのコードフラグメントがクリティカルセクションに属するかを分析します
  • 同期相互排除を使用して、クリティカルセクションのスレッドセーフの問題を解決します
  1. 同期されたロックオブジェクトの構文を把握する
  2. 同期されたロードメンバーメソッドと静的メソッドの構文をマスターする
  3. 待機/通知の同期方法を習得する
  • ロック相互排除を使用して、クリティカルセクションのスレッドセーフの問題を解決します
  1. ロックの使用の詳細をマスターする:割り込み可能、​​ロックタイムアウト、フェアロック、条件変数
  • 変数のスレッドセーフを分析し、一般的なスレッドセーフクラスの使用を習得する方法を学びます
  • スレッドアクティビティの問題を理解する:デッドロック、ライブロック、飢餓
  • アプリケーションの側面
  1. 相互排除:同期またはロックを使用して、共有リソースの相互排除を実現します
  2. 同期:待機/通知またはロック条件変数を使用して、スレッド間通信の効果を実現します

原理的側面

  • 監視、同期、待機/通知原理
  • 同期の高度な原理
  • パーク&アンパークの原則

モデルの側面

  • 同期モードでの保護一時停止
  • 非同期モードのプロデューサーとコンシューマー
  • 同期モードのシーケンス制御
     

おすすめ

転載: blog.csdn.net/nmjhehe/article/details/109631200