[J2SE1.4] スレッド2
排他制御
・synchronizedメソッドを使った排他制御
・synchronizedブロックを使った排他制御
[synchronizedメソッドを使った排他制御]
アクセス修飾子+synchronized+戻り値+メソッド名(引数リスト){...}
synchronizedメソッドには
非staticなものとstaticなもの
がある
・非staticなsynchronizedメソッド
synchronizedメソッドにあるスレッドにアクセスすると、
他のスレッドはこのメソッドにはアクセス出来なくなる。
→先にアクセスしたスレッドの処理が終わるまで待つ。
import java.util.ArrayList;
public class Monitor {
private ArrayList list = new ArrayList();
public synchronized void addObj(Object obj) {
list.add(obj);
}
}
Thread1がaddObjを実行中の間、
Thread2はaddObjにアクセス出来ない。
複数スレッドからアクセスされるオブジェクトを
スレッドプログラミングで[モニタ]という。
import java.util.ArrayList;
public class Monitor {
private ArrayList list = new ArrayList();
public synchronized void addObj(Object obj) {
list.add(obj);
}
public synchronized void removeObj(int idx) {
list.remove(idx);
}
public void getSize(int idx) {
list.size(idx);
}
}
Thread1がaddObjを実行中の間、
Thread2はremoveObjにもアクセス出来ない。
1つのsynchronizedメソッドが実行されている場合、
そのクラスに存在する全てのsynchronizedメソッドにロックがかかる。
クラス内の全てのsynchronizedメソッドは、シンクロし合って1セットとなる。
ただし、
synchronizedキーワードがついていない部分は排他制御の対象外
Thread1がaddObjを実行中の間も、
Thread2はgetSizeを実行できる。
要注意
フィールドlistを扱うメソッドaddObjとremoveObjにsynchronizedをつけても、
フィールドlist自体にロックがかかっていないので、
private以外のアクセス修飾子の、synchronizedでないメソッドでlistに意図せぬ変更をし得る。
・staticなsynchronizedメソッド
import java.util.ArrayList;
public class Monitor {
private static ArrayList list = new ArrayList();
public static synchronized void staticAddObj(Object obj) {
list.add(obj);
}
public static synchronized void staticRemoveObj(int i) {
if (i < list.size()) {
list.remove(i);
}
}
public synchronized void addObj(Object obj) {
list.add(obj);
}
public synchronized void removeObj(int i) {
if (i < list.size()) {
list.remove(i);
}
}
}
Thread1がstatidAddObjを実行中の間、
Thread2は
staticAddObjとstaticRemoveObjにはアクセス出来ないが、
addObjとremoveObjにはアクセス出来る。
Thread1がaddObjを実行中の間、
Thread2は
addObjとremoveObjにはアクセス出来ないが、
staticAddObjとstaticRemoveObjにはアクセス出来る。
非staticなsynchronizedメソッド同士
staticなsynchronizedメソッド同士
でシンクロする。
[synchronizedブロックを使った排他制御]
synchronizedメソッドでの排他制御:
全てのメソッドが対象になり、1クラスに1種類の排他制御しか出来ない。
synchronizedブロックでの排他制御:
多彩な排他制御の範囲を指定でき、複雑な排他制御も出来る。
synchronizedブロックの記述方法
synchronized (OBJECT) { ...... }
※OBJECT:
ロック用オブジェクト
synchronizedブロックを実行する為の権利みたいなもの
ロック用オブジェクトはObjectインスタンスでもStringインスタンスでも何でも可。
01:import java.utilArrayList;
02:public class Minitor {
03: public static ArrayList list = new ArrayList();
04: private Object lockObj = new Object();
05: public void addObj(Object obj) {
06: synchronized(lockObj) {
07: list.add(obj);
08: }
09: }
10:}
6行目でロック(ロックフラグ)を取得したスレッドのみが
synchronizedブロックの処理を続行できる。
Thread1がsynchronizedブロックを処理している間、
Thread2はlockObjを取得出来ないのでsynchronizedブロックを処理できない。
メソッド全体を排他制御の対象とするよりも、
メソッドの一部分だけを排他制御の対象とした方が、
排他制御の範囲を最小限に出来るため、パフォーマンスも上がる。
synchronizedブロックで複数種類の排他制御の実装
import java.util.ArrayList;
public class Monitor {
public static ArrayList list1 = new ArrayList();
public static ArrayList list2 = new ArrayList();
private Object lockObj1 = new Object();
private Object lockObj2 = new Object();
public void addObj1(Object obj) {
synchronized(lockObj1) {
list.add(obj);
}
}
public void addObj2(Object obj) {
synchronized(lockObj2) {
list.add(obj);
}
}
public synchronized void removeObj1(int i){
synchronized(lockObj1){
if(i < list.size()){
list1.remove(i);
}
}
}
public synchronized void removeObj2(int i){
synchronized(lockObj2){
if(i < list.size()){
list1.remove(i);
}
}
}
}
lockObjectはなんでもよい
import java.util.ArrayList;
public class Monitor {
public static ArrayList list = new ArrayList();
public void addObj1(Object obj){
synchronized(this){
list.add(obj);
}
}
public int getSize(Object obj){
return list.size();
}
}
単にロックオブジェクトが[this]なだけ。
synchronizedブロック内を実行中の間は、
他のスレッドが自分自身にアクセスできないわけでナイ。
自分自身のロックフラグを持っていないスレッドが synchronized ブロック内を実行できないだけ。
[list]や[getSize]にはアクセス可能。
--------------------------------------------------
Q1 間違ってるのは?
a. public class Car
b. public abstract class Car
c. public class Car implements Vehicle
d. public synchronized Car extends AutoMobil
A1
d
synchronizedは、
synchronized メソッドかsynchronized ブロックしか使用不可
--------------------------------------------------
Q2 ThreadAがstaticAddObj()を実行してる間に、ThreadBがアクセスできるメソッドは?
01:import java.util.ArrayList;
02:public class Monitor {
03: public static ArrayList list = new ArrayList();
04:
05: public static synchronized void static AddObj(Object obj) {
06: list.add(obj);
07: }
08:
09: public static synchronized void staticRemoveObj(int i) {
10: if (i < list.size()) {
11: list.remove(i);
12: }
13: }
14:
15: public synchronized void addObj(Object obj) {
16: list.add(obj);
17: }
18:
19: public synchronized void removeObj(int i) {
20: if (0 < list.size()) {
21: list.remove(i);
22: }
23: }
24:
25: public int getSize() {
26: list.size();
27: }
28:}
a. staticAddObj(Object obj)
b. staticRemoveObj(int i)
c. addObj(Object obj)
d. removeObj(int i)
e. getSize()
A2
×a. staticAddObj(Object obj)
×b. staticRemoveObj(int i)
○c. addObj(Object obj)
○d. removeObj(int i)
○e. getSize()
staticなsynchronizedメソッドは、他のstaticなsynchronizedメソッドとシンクロする。
非staticなsynchronizedメソッドは、他の非staticなsynchronizedメソッドとシンクロする。
→staticはstatic同士で、非staticは非static同士でシンクロする。
--------------------------------------------------
Q3 正しいのは?
1: public class Monitor {
2: private int num1;
3: private int num2;
4: void increase(){
5: num1 ++;
6: num2 ++;
7: System.out.println(num1 == num2);
8: }
9: }
10:
11: public class ThreadClass extends Thread {
12: private Monitor m;
13: public ThreadClass(Monitor m) {
14: this.m = m;
15: }
16: public void run() {
17: for (int i = 0; i < 1000; i++) {
18: m.increase();
19: }
20: }
21: }
22:
23: public class MainClass {
24: public static void main(String args[]){
25: Monitor m = new Monitor();
26: ThreadClass th1 = new ThreadClass(m);
27: ThreadClass th2 = new ThreadClass(m);
28: th1.start();
29: th2.start();
30: }
31: }
a. trueまたはfalseを表示することがある
b. 常にtrueを表示する
c. 常にfalseを表示する
d. 例外が発生する
A3
a
プログラムが実行されると二つのスレッドが
同一のMonitorクラスのオブジェクトmのincrease()メソッドを呼ぶ。
片方のスレッドがincrease()実行中にもう片方のスレッドがincrease()を実行すると、num1とnum2の値は等しくなくなるタイミングが出る。
--------------------------------------------------
Q4 必ずtrueと出力させるためには?
public class Monitor {
private int num1;
private int num2;
void increase() {
num1 ++;
num2 ++;
System.out.println(num1 == num2);
}
}
public classThreadClass extends Thread {
private Monitor m;
public ThreadClass(Monitor m) {
this.m = m;
}
public void run() {
for (int i=0; i<1000; i++) {
m.increase();
}
}
}
public class MainClass {
public static void main(String[] args) {
Monitor m = new Monitor();
ThreadClass th1 = new ThreadClass(m);
ThreadClass th2 = new ThreadClass(m);
th1.start();
th2.start();
}
}
a.Monitorクラスを変更
public class Monitor {
private int num1;
private int num2;
void synchronized increase() {
num1 ++; num2++;
syso(num1 == num2);
}
}
b.Monitorクラスを変更
public class Monitor {
private int num1;
private int num2;
void increase() {
synchronized(this) {
num1 ++; num2++;
syso(num1 == num2);
}
}
}
c.ThreadClassを変更
public class ThreadClass extends Thread {
private Monitor m;
public ThreadClass(Monitor m) {
this.m = m;
}
public void synchronized run() {
for (int i = 0; i < 1000; i++) {
m.increase();
}
}
}
c.ThreadClassを変更
public class ThreadClass extends Thread {
private Monitor m;
public ThreadClass(Monitor m) {
this.m = m;
}
public void run() {
synchronized(this) {
for (int i = 0; i < 1000; i++) {
m.increase();
}
}
}
}
A4
b
--------------------------------------------------
Q5 deposit()が実行中だとして 正しいのは?
public class Monitor {
private int account;
public synchronized void deposit(int money) {
account = account - money;
}
public synchronized void withdraw(int money) {
account = account + money;
}
public int getAccount() {
return account;
}
}
a. 他のスレッドはこのオブジェクトのどのメソッドも実行できない。
b. 他のスレッドはwithdraw()メソッドのみ実行できる。
c. 他のスレッドはgetAccount()メソッドのみ実行できる。
d. 他のスレッドは全メソッドを実行できる。
A5
c
--------------------------------------------------
Q6 正しいのは?
import java.util.ArrayList;
public class Monitor {
private static ArrayList list = new ArrayList();
private Object lockObj1 = new Object();
private Object lockObj2 = new Object();
public void addObj1(Object obj) {
synchronized(lockObj1) {
list.add(obj);
}
}
public void removeObj1(int i) {
synchronized(lockObj1) {
if (i < list.size()) {
list.remove(i);
}
}
}
public void removeObj2(int i) {
synchronized(lockObj2) {
if(i < list.size()) {
list.remove(i);
}
}
}
}
a. コンパイルエラー。
b. addObj1のlist.add(obj)で例外が出うる。
c. removeObj1のlist.remove(i)で例外が出うる。
d. removeObj2のlist.remove(i)で例外が出うる。
e. 例外なし。
A6
c, d
同じlistを扱うのに異なるロックオブジェクトを使っているため
同時に複数スレッドからlistを変更してしまいうる。
で、IndexOutOgBoundsExceptionが出うる。
goto [J2SE1.4] INDEX
・synchronizedメソッドを使った排他制御
・synchronizedブロックを使った排他制御
[synchronizedメソッドを使った排他制御]
アクセス修飾子+synchronized+戻り値+メソッド名(引数リスト){...}
synchronizedメソッドには
非staticなものとstaticなもの
がある
・非staticなsynchronizedメソッド
synchronizedメソッドにあるスレッドにアクセスすると、
他のスレッドはこのメソッドにはアクセス出来なくなる。
→先にアクセスしたスレッドの処理が終わるまで待つ。
import java.util.ArrayList;
public class Monitor {
private ArrayList list = new ArrayList();
public synchronized void addObj(Object obj) {
list.add(obj);
}
}
Thread1がaddObjを実行中の間、
Thread2はaddObjにアクセス出来ない。
複数スレッドからアクセスされるオブジェクトを
スレッドプログラミングで[モニタ]という。
import java.util.ArrayList;
public class Monitor {
private ArrayList list = new ArrayList();
public synchronized void addObj(Object obj) {
list.add(obj);
}
public synchronized void removeObj(int idx) {
list.remove(idx);
}
public void getSize(int idx) {
list.size(idx);
}
}
Thread1がaddObjを実行中の間、
Thread2はremoveObjにもアクセス出来ない。
1つのsynchronizedメソッドが実行されている場合、
そのクラスに存在する全てのsynchronizedメソッドにロックがかかる。
クラス内の全てのsynchronizedメソッドは、シンクロし合って1セットとなる。
ただし、
synchronizedキーワードがついていない部分は排他制御の対象外
Thread1がaddObjを実行中の間も、
Thread2はgetSizeを実行できる。
要注意
フィールドlistを扱うメソッドaddObjとremoveObjにsynchronizedをつけても、
フィールドlist自体にロックがかかっていないので、
private以外のアクセス修飾子の、synchronizedでないメソッドでlistに意図せぬ変更をし得る。
・staticなsynchronizedメソッド
import java.util.ArrayList;
public class Monitor {
private static ArrayList list = new ArrayList();
public static synchronized void staticAddObj(Object obj) {
list.add(obj);
}
public static synchronized void staticRemoveObj(int i) {
if (i < list.size()) {
list.remove(i);
}
}
public synchronized void addObj(Object obj) {
list.add(obj);
}
public synchronized void removeObj(int i) {
if (i < list.size()) {
list.remove(i);
}
}
}
Thread1がstatidAddObjを実行中の間、
Thread2は
staticAddObjとstaticRemoveObjにはアクセス出来ないが、
addObjとremoveObjにはアクセス出来る。
Thread1がaddObjを実行中の間、
Thread2は
addObjとremoveObjにはアクセス出来ないが、
staticAddObjとstaticRemoveObjにはアクセス出来る。
非staticなsynchronizedメソッド同士
staticなsynchronizedメソッド同士
でシンクロする。
[synchronizedブロックを使った排他制御]
synchronizedメソッドでの排他制御:
全てのメソッドが対象になり、1クラスに1種類の排他制御しか出来ない。
synchronizedブロックでの排他制御:
多彩な排他制御の範囲を指定でき、複雑な排他制御も出来る。
synchronizedブロックの記述方法
synchronized (OBJECT) { ...... }
※OBJECT:
ロック用オブジェクト
synchronizedブロックを実行する為の権利みたいなもの
ロック用オブジェクトはObjectインスタンスでもStringインスタンスでも何でも可。
01:import java.utilArrayList;
02:public class Minitor {
03: public static ArrayList list = new ArrayList();
04: private Object lockObj = new Object();
05: public void addObj(Object obj) {
06: synchronized(lockObj) {
07: list.add(obj);
08: }
09: }
10:}
6行目でロック(ロックフラグ)を取得したスレッドのみが
synchronizedブロックの処理を続行できる。
Thread1がsynchronizedブロックを処理している間、
Thread2はlockObjを取得出来ないのでsynchronizedブロックを処理できない。
メソッド全体を排他制御の対象とするよりも、
メソッドの一部分だけを排他制御の対象とした方が、
排他制御の範囲を最小限に出来るため、パフォーマンスも上がる。
synchronizedブロックで複数種類の排他制御の実装
import java.util.ArrayList;
public class Monitor {
public static ArrayList list1 = new ArrayList();
public static ArrayList list2 = new ArrayList();
private Object lockObj1 = new Object();
private Object lockObj2 = new Object();
public void addObj1(Object obj) {
synchronized(lockObj1) {
list.add(obj);
}
}
public void addObj2(Object obj) {
synchronized(lockObj2) {
list.add(obj);
}
}
public synchronized void removeObj1(int i){
synchronized(lockObj1){
if(i < list.size()){
list1.remove(i);
}
}
}
public synchronized void removeObj2(int i){
synchronized(lockObj2){
if(i < list.size()){
list1.remove(i);
}
}
}
}
lockObjectはなんでもよい
import java.util.ArrayList;
public class Monitor {
public static ArrayList list = new ArrayList();
public void addObj1(Object obj){
synchronized(this){
list.add(obj);
}
}
public int getSize(Object obj){
return list.size();
}
}
単にロックオブジェクトが[this]なだけ。
synchronizedブロック内を実行中の間は、
他のスレッドが自分自身にアクセスできないわけでナイ。
自分自身のロックフラグを持っていないスレッドが synchronized ブロック内を実行できないだけ。
[list]や[getSize]にはアクセス可能。
--------------------------------------------------
Q1 間違ってるのは?
a. public class Car
b. public abstract class Car
c. public class Car implements Vehicle
d. public synchronized Car extends AutoMobil
A1
d
synchronizedは、
synchronized メソッドかsynchronized ブロックしか使用不可
--------------------------------------------------
Q2 ThreadAがstaticAddObj()を実行してる間に、ThreadBがアクセスできるメソッドは?
01:import java.util.ArrayList;
02:public class Monitor {
03: public static ArrayList list = new ArrayList();
04:
05: public static synchronized void static AddObj(Object obj) {
06: list.add(obj);
07: }
08:
09: public static synchronized void staticRemoveObj(int i) {
10: if (i < list.size()) {
11: list.remove(i);
12: }
13: }
14:
15: public synchronized void addObj(Object obj) {
16: list.add(obj);
17: }
18:
19: public synchronized void removeObj(int i) {
20: if (0 < list.size()) {
21: list.remove(i);
22: }
23: }
24:
25: public int getSize() {
26: list.size();
27: }
28:}
a. staticAddObj(Object obj)
b. staticRemoveObj(int i)
c. addObj(Object obj)
d. removeObj(int i)
e. getSize()
A2
×a. staticAddObj(Object obj)
×b. staticRemoveObj(int i)
○c. addObj(Object obj)
○d. removeObj(int i)
○e. getSize()
staticなsynchronizedメソッドは、他のstaticなsynchronizedメソッドとシンクロする。
非staticなsynchronizedメソッドは、他の非staticなsynchronizedメソッドとシンクロする。
→staticはstatic同士で、非staticは非static同士でシンクロする。
--------------------------------------------------
Q3 正しいのは?
1: public class Monitor {
2: private int num1;
3: private int num2;
4: void increase(){
5: num1 ++;
6: num2 ++;
7: System.out.println(num1 == num2);
8: }
9: }
10:
11: public class ThreadClass extends Thread {
12: private Monitor m;
13: public ThreadClass(Monitor m) {
14: this.m = m;
15: }
16: public void run() {
17: for (int i = 0; i < 1000; i++) {
18: m.increase();
19: }
20: }
21: }
22:
23: public class MainClass {
24: public static void main(String args[]){
25: Monitor m = new Monitor();
26: ThreadClass th1 = new ThreadClass(m);
27: ThreadClass th2 = new ThreadClass(m);
28: th1.start();
29: th2.start();
30: }
31: }
a. trueまたはfalseを表示することがある
b. 常にtrueを表示する
c. 常にfalseを表示する
d. 例外が発生する
A3
a
プログラムが実行されると二つのスレッドが
同一のMonitorクラスのオブジェクトmのincrease()メソッドを呼ぶ。
片方のスレッドがincrease()実行中にもう片方のスレッドがincrease()を実行すると、num1とnum2の値は等しくなくなるタイミングが出る。
--------------------------------------------------
Q4 必ずtrueと出力させるためには?
public class Monitor {
private int num1;
private int num2;
void increase() {
num1 ++;
num2 ++;
System.out.println(num1 == num2);
}
}
public classThreadClass extends Thread {
private Monitor m;
public ThreadClass(Monitor m) {
this.m = m;
}
public void run() {
for (int i=0; i<1000; i++) {
m.increase();
}
}
}
public class MainClass {
public static void main(String[] args) {
Monitor m = new Monitor();
ThreadClass th1 = new ThreadClass(m);
ThreadClass th2 = new ThreadClass(m);
th1.start();
th2.start();
}
}
a.Monitorクラスを変更
public class Monitor {
private int num1;
private int num2;
void synchronized increase() {
num1 ++; num2++;
syso(num1 == num2);
}
}
b.Monitorクラスを変更
public class Monitor {
private int num1;
private int num2;
void increase() {
synchronized(this) {
num1 ++; num2++;
syso(num1 == num2);
}
}
}
c.ThreadClassを変更
public class ThreadClass extends Thread {
private Monitor m;
public ThreadClass(Monitor m) {
this.m = m;
}
public void synchronized run() {
for (int i = 0; i < 1000; i++) {
m.increase();
}
}
}
c.ThreadClassを変更
public class ThreadClass extends Thread {
private Monitor m;
public ThreadClass(Monitor m) {
this.m = m;
}
public void run() {
synchronized(this) {
for (int i = 0; i < 1000; i++) {
m.increase();
}
}
}
}
A4
b
--------------------------------------------------
Q5 deposit()が実行中だとして 正しいのは?
public class Monitor {
private int account;
public synchronized void deposit(int money) {
account = account - money;
}
public synchronized void withdraw(int money) {
account = account + money;
}
public int getAccount() {
return account;
}
}
a. 他のスレッドはこのオブジェクトのどのメソッドも実行できない。
b. 他のスレッドはwithdraw()メソッドのみ実行できる。
c. 他のスレッドはgetAccount()メソッドのみ実行できる。
d. 他のスレッドは全メソッドを実行できる。
A5
c
--------------------------------------------------
Q6 正しいのは?
import java.util.ArrayList;
public class Monitor {
private static ArrayList list = new ArrayList();
private Object lockObj1 = new Object();
private Object lockObj2 = new Object();
public void addObj1(Object obj) {
synchronized(lockObj1) {
list.add(obj);
}
}
public void removeObj1(int i) {
synchronized(lockObj1) {
if (i < list.size()) {
list.remove(i);
}
}
}
public void removeObj2(int i) {
synchronized(lockObj2) {
if(i < list.size()) {
list.remove(i);
}
}
}
}
a. コンパイルエラー。
b. addObj1のlist.add(obj)で例外が出うる。
c. removeObj1のlist.remove(i)で例外が出うる。
d. removeObj2のlist.remove(i)で例外が出うる。
e. 例外なし。
A6
c, d
同じlistを扱うのに異なるロックオブジェクトを使っているため
同時に複数スレッドからlistを変更してしまいうる。
で、IndexOutOgBoundsExceptionが出うる。
goto [J2SE1.4] INDEX
