プログラマメモ: ロックのサンプルをつくってみた
2006/06/23
2006/11/26
プログラマメモ: ロックのサンプルをつくってみた
以前書いた記事への補完です。
適当にアップしてます。
#どこかの機会できちんとまとめたいです。
より厳密にスレッドの実験を行う場合は、
Thread.yield();
を使うといいようです。
とありました。
会社でJavaに詳しい人に教えていただきました。
より厳密に動作するようにしてみました。
絶対要件
処理のa b cと決まった順序で実行されることを保証することです。
public class TestThread_synchronized_block {
Lock lock;
public static void main(String[] args) {
final TestThread_synchronized_block testLock = new TestThread_synchronized_block();
new Thread(createRunnable(testLock)).start();
new Thread(createRunnable(testLock)).start();
new Thread(createRunnable(testLock)).start();
}
public static Runnable createRunnable(final TestThread_synchronized_block th) {
return new Runnable() {
public void run() {
try {
while (true) {
th.go();
Thread.sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
public TestThread_synchronized_block() {
this.lock = new Lock();
}
int checkCont = 0;
public void go() throws InterruptedException {
if (!lock.lock()) {
return;
}
try {
Thread.yield(); // (1) ここで他スレッドに処理が移る
a();
Thread.yield(); // (2) ここで他スレッドに処理が移る
b();
Thread.yield(); // (3) ここで他スレッドに処理が移る
c();
Thread.yield(); // (4) ここで他スレッドに処理が移る
if (checkCont == 3) {
System.out.println("not broken!!");
} else {
System.out.println("BROKEN!!");
System.exit(0);
}
} finally {
checkCont = 0;
lock.release();
}
}
public void a() throws InterruptedException {
System.out.println(" process a " + Thread.currentThread());
checkCont++;
}
public void b() throws InterruptedException {
System.out.println(" process b " + Thread.currentThread());
checkCont++;
}
public void c() throws InterruptedException {
System.out.println(" process c " + Thread.currentThread());
checkCont++;
}
class Lock {
private boolean locked = false;
public boolean lock() {
/*
* using synchronized block
*/
synchronized (this) {
if (locked) {
return false;
}
locked = true;
return true;
}
}
public void release() {
/*
* using synchronized block
*/
synchronized (this) {
this.locked = false;
}
}
}
}
厳密に動く別バージョンです。
public class TestThread_another_version {
private volatile Lock lock = new Lock();
public static void main(String[] args) {
final TestThread_another_version testLock = new TestThread_another_version();
new Thread(createRunnable(testLock)).start();
new Thread(createRunnable(testLock)).start();
new Thread(createRunnable(testLock)).start();
}
public static Runnable createRunnable(final TestThread_another_version th) {
return new Runnable() {
public void run() {
try {
while (true) {
th.go();
Thread.sleep(3);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
public TestThread_another_version() {
}
int checkCont = 0;
public void go() throws InterruptedException {
if (lock.tryLock()) {
try {
Thread.yield();
a();
Thread.yield();
b();
Thread.yield();
c();
Thread.yield();
if (checkCont == 3) {
System.out.println("not broken!!");
} else {
System.out.println("BROKEN!!");
System.exit(0);
}
}
finally {
checkCont = 0;
lock.unLock();
}
}
}
public void a() throws InterruptedException {
System.out.println (" process a " + Thread.currentThread());
checkCont++;
}
public void b() throws InterruptedException {
System.out.println(" process b " + Thread.currentThread ());
checkCont++;
}
public void c() throws InterruptedException {
System.out.println(" process c " + Thread.currentThread());
checkCont++;
}
private static final class Lock {
public synchronized boolean tryLock() {
Thread.yield();
if (locked) {
Thread.yield();
return false;
} else {
Thread.yield();
locked = true;
Thread.yield();
return true;
}
}
public void unLock() {
Thread.yield();
locked = false;
Thread.yield();
}
private volatile boolean locked;
}
}
NYSLのもといただいたコードです。
public final class TestThread_4 {
public static void main(String[] args) {
final TestThread_4 testLock = new TestThread_4();
for (int i = 0, n = 10; i < n; ++i) {
new Thread(createRunnable(testLock)).start();
}
}
public static Runnable createRunnable(final TestThread_4 testThread_4) {
return new Runnable() {
public void run() {
while (true) {
testThread_4.go();
}
}
};
}
public void go() {
Thread.yield();
if (lock.tryLock()) {
try {
Thread.yield();
a();
Thread.yield();
b();
Thread.yield();
c();
Thread.yield();
}
finally {
lock.unLock();
}
}
}
public void a() {
System.out.println(" process a " + Thread.currentThread() + ": " + this.toString());
}
public void b() {
System.out.println(" process b " + Thread.currentThread() + ": " + this.toString());
}
public void c() {
System.out.println(" process c " + Thread.currentThread() + ": " + this.toString());
}
private static final class Lock {
public synchronized boolean tryLock() {
if (locked) {
return false;
} else {
locked = true;
return true;
}
}
public synchronized void unLock() {
locked = false;
}
private volatile boolean locked;
}
private volatile Lock lock = new Lock();
}
以前書いた記事への補完です。
適当にアップしてます。
#どこかの機会できちんとまとめたいです。
より厳密にスレッドの実験を行う場合は、
Thread.yield();
を使うといいようです。
「ほとんどのプログラマによるThread.yieldの唯一の使い方は、テスト中にプログラムの平行性を意図的に増加させることです。」
「Effective Java」P.194
とありました。
会社でJavaに詳しい人に教えていただきました。
より厳密に動作するようにしてみました。
絶対要件
処理のa b cと決まった順序で実行されることを保証することです。
public class TestThread_synchronized_block {
Lock lock;
public static void main(String[] args) {
final TestThread_synchronized_block testLock = new TestThread_synchronized_block();
new Thread(createRunnable(testLock)).start();
new Thread(createRunnable(testLock)).start();
new Thread(createRunnable(testLock)).start();
}
public static Runnable createRunnable(final TestThread_synchronized_block th) {
return new Runnable() {
public void run() {
try {
while (true) {
th.go();
Thread.sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
public TestThread_synchronized_block() {
this.lock = new Lock();
}
int checkCont = 0;
public void go() throws InterruptedException {
if (!lock.lock()) {
return;
}
try {
Thread.yield(); // (1) ここで他スレッドに処理が移る
a();
Thread.yield(); // (2) ここで他スレッドに処理が移る
b();
Thread.yield(); // (3) ここで他スレッドに処理が移る
c();
Thread.yield(); // (4) ここで他スレッドに処理が移る
if (checkCont == 3) {
System.out.println("not broken!!");
} else {
System.out.println("BROKEN!!");
System.exit(0);
}
} finally {
checkCont = 0;
lock.release();
}
}
public void a() throws InterruptedException {
System.out.println(" process a " + Thread.currentThread());
checkCont++;
}
public void b() throws InterruptedException {
System.out.println(" process b " + Thread.currentThread());
checkCont++;
}
public void c() throws InterruptedException {
System.out.println(" process c " + Thread.currentThread());
checkCont++;
}
class Lock {
private boolean locked = false;
public boolean lock() {
/*
* using synchronized block
*/
synchronized (this) {
if (locked) {
return false;
}
locked = true;
return true;
}
}
public void release() {
/*
* using synchronized block
*/
synchronized (this) {
this.locked = false;
}
}
}
}
厳密に動く別バージョンです。
public class TestThread_another_version {
private volatile Lock lock = new Lock();
public static void main(String[] args) {
final TestThread_another_version testLock = new TestThread_another_version();
new Thread(createRunnable(testLock)).start();
new Thread(createRunnable(testLock)).start();
new Thread(createRunnable(testLock)).start();
}
public static Runnable createRunnable(final TestThread_another_version th) {
return new Runnable() {
public void run() {
try {
while (true) {
th.go();
Thread.sleep(3);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
public TestThread_another_version() {
}
int checkCont = 0;
public void go() throws InterruptedException {
if (lock.tryLock()) {
try {
Thread.yield();
a();
Thread.yield();
b();
Thread.yield();
c();
Thread.yield();
if (checkCont == 3) {
System.out.println("not broken!!");
} else {
System.out.println("BROKEN!!");
System.exit(0);
}
}
finally {
checkCont = 0;
lock.unLock();
}
}
}
public void a() throws InterruptedException {
System.out.println (" process a " + Thread.currentThread());
checkCont++;
}
public void b() throws InterruptedException {
System.out.println(" process b " + Thread.currentThread ());
checkCont++;
}
public void c() throws InterruptedException {
System.out.println(" process c " + Thread.currentThread());
checkCont++;
}
private static final class Lock {
public synchronized boolean tryLock() {
Thread.yield();
if (locked) {
Thread.yield();
return false;
} else {
Thread.yield();
locked = true;
Thread.yield();
return true;
}
}
public void unLock() {
Thread.yield();
locked = false;
Thread.yield();
}
private volatile boolean locked;
}
}
NYSLのもといただいたコードです。
public final class TestThread_4 {
public static void main(String[] args) {
final TestThread_4 testLock = new TestThread_4();
for (int i = 0, n = 10; i < n; ++i) {
new Thread(createRunnable(testLock)).start();
}
}
public static Runnable createRunnable(final TestThread_4 testThread_4) {
return new Runnable() {
public void run() {
while (true) {
testThread_4.go();
}
}
};
}
public void go() {
Thread.yield();
if (lock.tryLock()) {
try {
Thread.yield();
a();
Thread.yield();
b();
Thread.yield();
c();
Thread.yield();
}
finally {
lock.unLock();
}
}
}
public void a() {
System.out.println(" process a " + Thread.currentThread() + ": " + this.toString());
}
public void b() {
System.out.println(" process b " + Thread.currentThread() + ": " + this.toString());
}
public void c() {
System.out.println(" process c " + Thread.currentThread() + ": " + this.toString());
}
private static final class Lock {
public synchronized boolean tryLock() {
if (locked) {
return false;
} else {
locked = true;
return true;
}
}
public synchronized void unLock() {
locked = false;
}
private volatile boolean locked;
}
private volatile Lock lock = new Lock();
}
: