Javaマルチスレッドに関する知識【12】--設計モード--読み書きロックモード(読み書きモード)
55125 ワード
文書ディレクトリ Javaマルチスレッドに関する知識【12】--設計モード--読み書きロックモード(読み書きモード) 1.問題の導入 問題発生コード .ソリューション 解決の原理 コード実装 読み書きロックの実装 3.ステップアップソリューション 問題の導入 解決の原理 コード実装 読み書きロック 共有データ リードスレッド 書き込みスレッド 読み書きロックの欠陥 欠陥の分析 欠陥の解決 解決の実装コード 読み書きロック改良 Javaマルチスレッドに関する知識【12】–設計モード–読み書きロックモード(読み書きモード)
1.問題の導入
今、観光地があると仮定して、この観光地にも切符検査員が一人しかいません.彼の仕事はお客様の切符を手に入れて、切符の副切符を引き裂いて、副切符以外の部分を観光客に返すことです.普段、客の流れはそれほど大きくないので、彼は間違いを犯すことはありません.
しかしある日、この観光地は急に高く宣伝され、一気に多くの人がこの観光地に押し寄せた.
客の流れが大きくなるにつれて、長い間の疲労の仕事と、この切符検査員はついに客の流れの試練に耐えられず、一部の観光客は直接切符を彼に渡したが、彼はタイムリーに切符を観光客に返さなかったが、後の観光客はまた彼の切符を渡した.
仕事のミスで、彼は社長に給料を引かれた.
Javaマルチスレッドでは,このような問題は,複数のスレッドが共有データを同時に操作する場合に生じる問題である可能性がある.
問題が発生したコード
2.ソリューション
解決の原理
上の問題の出現について、主管者は1つの解決方法を思いついた.すなわち、主管は切符検査員の給料を差し引いて、また複数の警備員を呼んで、園区の各位置で、同時に、2人の警備員を手配して、切符検査員の切符検査の秩序維持を助けた.
Javaでは、対応する読み書きが必要なプロセスをロックして保護できます.
コード実装
読み書きロックの実装
3.ステップアップソリューション
問題の導入
観光地の事件について続けて言えば、園区に入ってから、一人一人が一つの観光地を見学するとき、警備員が厳格に秩序を守っているため、園区の内部の観光地ごとに毎日の観光客が急激に減少し、マネージャーを悩ませている.
解決の原理
マネージャーはこのような状況が発生した問題を詳しく分析した.園区の内部では、人々が観光地を見学する際、再び切符を調べる必要はないが、大量の警備員を使って秩序を維持し続けると効率が低下し、固経理は園区内の観光地前の警備を減らした.
Javaでは、このような状況の発生は、データを読むプログラムと、データを書くプログラムとに相当し、複数人が同時に読むことができるが、同時に1人だけデータの書き込み操作を行うことができる.
具体的な操作は以下の通りです.
実行中のプログラムの性質
実行するプログラムの性質
読み取り可能
リードロックをかけるかどうか
書き込み可能
書き込みロックをかけるかどうか
リードオペレーション
リードオペレーション
-
-
書き込み操作
-
-
書き込み操作
リードオペレーション
-
-
書き込み操作
-
-
コード実装
リードライトロック
データの共有
リードスレッド
書き込みスレッド
読み書きロックの欠陥
欠陥の分析
リードスレッドの限られたレベルが高いため、ライトスレッドは常にスレッドの変更ができないため、リードスレッドはファイルを占有し続け、ライトができず、データの更新ができません.
欠陥の解決
上記の問題を解決するために、書き込みスレッドに優先識別ビットを追加することで、関連する問題を解決できます.
解決された実装コード
リードライトロックの改良
1.問題の導入
今、観光地があると仮定して、この観光地にも切符検査員が一人しかいません.彼の仕事はお客様の切符を手に入れて、切符の副切符を引き裂いて、副切符以外の部分を観光客に返すことです.普段、客の流れはそれほど大きくないので、彼は間違いを犯すことはありません.
しかしある日、この観光地は急に高く宣伝され、一気に多くの人がこの観光地に押し寄せた.
客の流れが大きくなるにつれて、長い間の疲労の仕事と、この切符検査員はついに客の流れの試練に耐えられず、一部の観光客は直接切符を彼に渡したが、彼はタイムリーに切符を観光客に返さなかったが、後の観光客はまた彼の切符を渡した.
仕事のミスで、彼は社長に給料を引かれた.
Javaマルチスレッドでは,このような問題は,複数のスレッドが共有データを同時に操作する場合に生じる問題である可能性がある.
問題が発生したコード
/**
*
*/
public class NoLockToWork {
private String mainData;
private String lastData;
private int i=0;
public void check(String d,String f) throws InterruptedException {
mainData=d;
lastData=f;
i++;
verify();
}
private void verify() throws InterruptedException {
if(!mainData.equals(lastData)){
System.out.print("***********error*************");
System.out.println("NO."+i+" "+mainData+" is "+lastData);
wait();
}
}
public static void main(String[] args) {
NoLockToWork work=new NoLockToWork();
new Thread(()->{
while (true){
try {
work.check("10000","10000");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
while (true){
try {
work.check("20000","20000");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
while (true){
try {
work.check("30000","30000");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
2.ソリューション
解決の原理
上の問題の出現について、主管者は1つの解決方法を思いついた.すなわち、主管は切符検査員の給料を差し引いて、また複数の警備員を呼んで、園区の各位置で、同時に、2人の警備員を手配して、切符検査員の切符検査の秩序維持を助けた.
Javaでは、対応する読み書きが必要なプロセスをロックして保護できます.
コード実装
読み書きロックの実装
/**
*
*/
public class AddLockToWork {
private String mainData;
private String lastData;
private int i=0;
public void check(String d,String f) throws InterruptedException {
mainData=d;
lastData=f;
i++;
verify();
}
// ( )
private synchronized void verify() throws InterruptedException {
if(!mainData.equals(lastData)){
System.out.print("***********error*************");
System.out.println("NO."+i+" "+mainData+" is "+lastData);
wait();
}
}
public static void main(String[] args) {
NoLockToWork work=new NoLockToWork();
new Thread(()->{
while (true){
try {
work.check("10000","10000");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
while (true){
try {
work.check("20000","20000");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
while (true){
try {
work.check("30000","30000");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
3.ステップアップソリューション
問題の導入
観光地の事件について続けて言えば、園区に入ってから、一人一人が一つの観光地を見学するとき、警備員が厳格に秩序を守っているため、園区の内部の観光地ごとに毎日の観光客が急激に減少し、マネージャーを悩ませている.
解決の原理
マネージャーはこのような状況が発生した問題を詳しく分析した.園区の内部では、人々が観光地を見学する際、再び切符を調べる必要はないが、大量の警備員を使って秩序を維持し続けると効率が低下し、固経理は園区内の観光地前の警備を減らした.
Javaでは、このような状況の発生は、データを読むプログラムと、データを書くプログラムとに相当し、複数人が同時に読むことができるが、同時に1人だけデータの書き込み操作を行うことができる.
具体的な操作は以下の通りです.
実行中のプログラムの性質
実行するプログラムの性質
読み取り可能
リードロックをかけるかどうか
書き込み可能
書き込みロックをかけるかどうか
リードオペレーション
リードオペレーション
-
-
書き込み操作
-
-
書き込み操作
リードオペレーション
-
-
書き込み操作
-
-
コード実装
リードライトロック
/**
*
*/
public class ReadWriteLock {
/**
*
*/
private int waitReading = 0;
/**
*
*/
private int workReading = 0;
/**
*
*/
private int waitWriting = 0;
/**
* ( )
*/
private int workWriting = 0;
/**
* ,
*
* @throws InterruptedException
*/
public synchronized void readLock() throws InterruptedException {
try {
waitReading++;
while (workWriting > 0)
this.wait();
workReading++;
} finally {
waitReading--;
}
}
/**
*
*/
public synchronized void readUnLock() {
workReading--;
this.notifyAll();
}
/**
* ,
* @throws InterruptedException
*/
public synchronized void writLock() throws InterruptedException {
try {
waitWriting++;
while (workWriting > 0 || workReading > 0)
this.wait();
workWriting++;
} finally {
waitWriting--;
}
}
/**
*
*/
public synchronized void writUnLock() {
workWriting--;
this.notifyAll();
}
}
データの共有
public class ReadWriteShareData {
private final ReadWriteLock LOCK = new ReadWriteLock();
private int data = 0;
public void read() throws InterruptedException {
LOCK.readLock();
IntStream.rangeClosed(1, 10).forEach(i -> {
if (i == 10)
System.out.println();
else
System.out.print(data);
});
Thread.sleep(100);
LOCK.readUnLock();
}
public void write(int data) throws InterruptedException {
LOCK.writLock();
this.data=data;
LOCK.writUnLock();
}
}
リードスレッド
public class UsingReadWriteLockReader <T> extends Thread {
private T data = null;
public UsingReadWriteLockReader(T data) {
this.data = data;
}
@Override
public void run() {
try {
while (true){
if(data.getClass()==ReadWriteShareData.class)
((ReadWriteShareData)data).read();
else if (data.getClass()==ReadWriteShareDataWriteFirst.class)
((ReadWriteShareDataWriteFirst)data).read();
else
System.out.println("error");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
書き込みスレッド
public class UsingReadWriteLockWriter<T> extends Thread {
private T data = null;
private int writeData = 0;
public UsingReadWriteLockWriter(T data, int writeData) {
this.data = data;
this.writeData = writeData;
}
@Override
public void run() {
try {
while (true)
if(data.getClass()==ReadWriteShareData.class)
((ReadWriteShareData)data).write(writeData);
else if (data.getClass()==ReadWriteShareDataWriteFirst.class)
((ReadWriteShareDataWriteFirst)data).write(writeData);
else
System.out.println("error");
} catch (InterruptedException e) {
// e.printStackTrace();
}
}
}
読み書きロックの欠陥
欠陥の分析
リードスレッドの限られたレベルが高いため、ライトスレッドは常にスレッドの変更ができないため、リードスレッドはファイルを占有し続け、ライトができず、データの更新ができません.
欠陥の解決
上記の問題を解決するために、書き込みスレッドに優先識別ビットを追加することで、関連する問題を解決できます.
解決された実装コード
リードライトロックの改良
/**
* ,
*/
public class ReadWriteLockWriteFirst {
/**
*
*/
private int waitReading = 0;
/**
*
*/
private int workReading = 0;
/**
*
*/
private int waitWriting = 0;
/**
* ( )
*/
private int workWriting = 0;
/**
*
*/
private boolean writerFirst=false;
public ReadWriteLockWriteFirst() {
this(true);
}
public ReadWriteLockWriteFirst(boolean writerFirst) {
this.writerFirst = writerFirst;
}
/**
* ,
*
* @throws InterruptedException
*/
public synchronized void readLock() throws InterruptedException {
try {
waitReading++;
//
while (workWriting > 0||(writerFirst&&waitWriting>0))
this.wait();
workReading++;
} finally {
waitReading--;
}
}
/**
*
*/
public synchronized void readUnLock() {
workReading--;
this.notifyAll();
}
/**
* ,
* @throws InterruptedException
*/
public synchronized void writLock() throws InterruptedException {
try {
waitWriting++;
while (workWriting > 0 || workReading > 0)
this.wait();
workWriting++;
} finally {
waitWriting--;
}
}
/**
*
*/
public synchronized void writUnLock() {
workWriting--;
this.notifyAll();
}
}