1つの面接問題は4つのスレッドを設計し、そのうち2つはjに対して1増加し、他の2つはjに対して1減少した.100回循環する.
タイトル
2つのスレッドがjに対して1ずつ増加し、2つのスレッドがjに対して1ずつ減少する4つのスレッドを設計する.100回循環する.プログラムを書き出します.
解法1
本の答えは内部類で実現され、ネット上の答えは基本的に本の上を写している.優雅な感じではなく、自分で以下を実現したい.
なお、同期が正しく実現されると、最後の出力は0となる.同期が正しくない場合、j++の途中ステップtemp=j+1が発生する可能性があります.またj-1が行われると,最後の結果は0ではない.
ここでsynchronizedキーワードのロード方法の前にあるクラスのインスタンスに対してロックされています.つまり、構造関数のパラメータとしてThreadクラスに渡すTestインスタンスは1つしかありません.次に、インスタンスのj変数操作に適したスレッドがロックされ、他のスレッドがj操作に対してロックの解放を待つ必要がある.これにより同期が実現します.
本コードの出力はいずれも0である.
非同期
synchronizedキーワードを削除し,sleep(100)を加えることでスレッド競合の可能性を増大させることができる.
結果1
結果2
同期していないため、最終的な結果は予知できないことがわかります.
内部クラスメソッド
ネット上の文章を参考にして、ここの注釈はとても詳しいです.
出力結果は最後も0であり,スレッド実行の順序は固定されていないが,最後の結果はいずれも0である.
参考記事
2つのスレッドがjに対して1ずつ増加し、2つのスレッドがjに対して1ずつ減少する4つのスレッドを設計する.プログラムを書き出します.2つのスレッドがjに対して1ずつ増加し、2つのスレッドがjに対して1ずつ減少する4つのスレッドを設計する.
2つのスレッドがjに対して1ずつ増加し、2つのスレッドがjに対して1ずつ減少する4つのスレッドを設計する.100回循環する.プログラムを書き出します.
解法1
本の答えは内部類で実現され、ネット上の答えは基本的に本の上を写している.優雅な感じではなく、自分で以下を実現したい.
package a;
public class Test {
private int j;
public static void main(String[] args) {
Test t = new Test();
for(int i =0;i<2;i++) {
Thread t1 = new Inc(t);
t1.start();
Thread t2 = new Dec(t);
t2.start();
}
}
public synchronized void inc() {
j++;
System.out.println(Thread.currentThread().getName() + ":inc" + j);
}
public synchronized void dec() {
j--;
System.out.println(Thread.currentThread().getName() + ":dec" + j);
}
}
class Inc extends Thread {
private Test a;
Inc(Test a) {
this.a = a;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
a.inc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Dec extends Thread {
private Test a;
Dec(Test a) {
this.a = a;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
a.dec();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
なお、同期が正しく実現されると、最後の出力は0となる.同期が正しくない場合、j++の途中ステップtemp=j+1が発生する可能性があります.またj-1が行われると,最後の結果は0ではない.
ここでsynchronizedキーワードのロード方法の前にあるクラスのインスタンスに対してロックされています.つまり、構造関数のパラメータとしてThreadクラスに渡すTestインスタンスは1つしかありません.次に、インスタンスのj変数操作に適したスレッドがロックされ、他のスレッドがj操作に対してロックの解放を待つ必要がある.これにより同期が実現します.
本コードの出力はいずれも0である.
Thread-1:dec0
Thread-2:inc1
Thread-3:dec0
Thread-0:inc1
Thread-1:dec0
Thread-2:inc1
Thread-3:dec0
Thread-0:inc1
Thread-1:dec0
非同期
synchronizedキーワードを削除し,sleep(100)を加えることでスレッド競合の可能性を増大させることができる.
public void inc() {
j++;
System.out.println(Thread.currentThread().getName() + ":inc" + j);
}
public void dec() {
j--;
System.out.println(Thread.currentThread().getName() + ":dec" + j);
}
結果1
Thread-3:dec-8
Thread-2:inc-8
Thread-1:dec-8
Thread-2:inc-7
Thread-0:inc-6
Thread-3:dec-7
Thread-1:dec-7
結果2
Thread-1:dec11
Thread-2:inc12
Thread-3:dec11
Thread-0:inc11
Thread-1:dec10
Thread-2:inc11
Thread-3:dec11
Thread-0:inc11
Thread-1:dec12
Thread-2:inc12
同期していないため、最終的な結果は予知できないことがわかります.
内部クラスメソッド
ネット上の文章を参考にして、ここの注釈はとても詳しいです.
package a;
public class ManyThread {
// Runnable
private int i;
//
private synchronized void inc() {
i++;
System.out.println(Thread.currentThread().getName() + "--inc--" + i);
}
//
private synchronized void dec() {
i--;
System.out.println(Thread.currentThread().getName() + "--dec--" + i);
}
// ,
class Inc implements Runnable {
public void run() {
int i = 0;
while (i++ < 100) {
inc();
}
}
}
// ,
class Dec extends Thread {
public void run() {
int i = 0;
while (i++ < 100) {
dec();
}
}
}
public static void main(String[] args) {
// , Test
ManyThread t = new ManyThread();
//
Inc inc = t.new Inc(); //
// Dec dec = t. new Dec();
Thread thread = null;
// 2
for (int i = 0; i < 2; i++) {
thread = new Thread(inc); // Runnable , Thread .
thread.start();
}
// 2
for (int i = 0; i < 2; i++) {
thread = t.new Dec(); // Thread .
thread.start();
}
}
}
出力結果は最後も0であり,スレッド実行の順序は固定されていないが,最後の結果はいずれも0である.
Thread-3--dec--7
Thread-3--dec--6
Thread-3--dec--5
Thread-3--dec--4
Thread-3--dec--3
Thread-3--dec--2
Thread-3--dec--1
Thread-3--dec--0
参考記事
2つのスレッドがjに対して1ずつ増加し、2つのスレッドがjに対して1ずつ減少する4つのスレッドを設計する.プログラムを書き出します.2つのスレッドがjに対して1ずつ増加し、2つのスレッドがjに対して1ずつ減少する4つのスレッドを設計する.