2

JavaのSemaphoreクラスを使用して作成された次の同時実行コードは、コンソール出力に従って、さらに困難なデッドロックに入り、許可が解放されています。

package ThreadTraining;

import java.util.concurrent.Semaphore;

public class ThreadTraining {

    public static class Value {

        private static int value = 0;
        private static final Semaphore SEMAPHORE = new Semaphore(1);

        public static synchronized void acquire() throws InterruptedException {
            SEMAPHORE.acquire();
            System.out.println("A thread has aquired a permit!");
        }

        public static synchronized void release() {
            SEMAPHORE.release();
        }

        public static int get() {
            return value;
        }

        public static void add() {
            value++;
        }

        public static void subtract() {
            value--;
        }
    }

    public static class Adder extends Thread {

        public Adder(String name) {
            this.setName(name);
        }

        @Override
        public void run() {
            System.out.println(this.getName() + " has been created.");
            boolean keepRunning = true;
            while (keepRunning) {
                try {
                    Value.acquire();
                    System.out.print(this.getName() + " has aquired Value's permit. --- ");
                    if (Value.get() > 99) {
                        System.out.print(this.getName() + " has finished it's job. --- ");
                        keepRunning = false;
                    } else {
                        System.out.print(this.getName() + " has modified value from " + Value.get() + "  to ");
                        Value.add();
                        System.out.println(Value.get() + ".");
                    }
                } catch (InterruptedException ie) {
                    System.err.println("This thread was interrupted.");
                } finally {
                    System.out.println(this.getName() + " is releasing Value's permit.");
                    Value.release();
                }
            }
        }
    }

    public static void main(String[] args) {
        Thread threads[] = new Thread[3];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Adder("[Adder]Thread #" + i);
        }
        for (Thread t : threads) {
            t.start();
        }
    }
}

コードのコンソール出力:(これは「幸運な」実行でした。通常、指定されたポイントまでしか印刷されません)

[Adder]Thread #0 has been created.
[Adder]Thread #1 has been created.
[Adder]Thread #2 has been created.
A thread has aquired a permit!
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 0  to 1.
[Adder]Thread #0 is releasing Value's permit. /*NOTE: It usually prints only up to this line, hanging after the first permit-release.*/
A thread has aquired a permit!
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 1  to 2.
[Adder]Thread #0 is releasing Value's permit.
A thread has aquired a permit!
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 2  to 3.
[Adder]Thread #0 is releasing Value's permit.
A thread has aquired a permit!
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 3  to 4.
[Adder]Thread #0 is releasing Value's permit.
A thread has aquired a permit!
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 4  to 5.
[Adder]Thread #0 is releasing Value's permit.
A thread has aquired a permit!
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 5  to 6.
[Adder]Thread #0 is releasing Value's permit.
A thread has aquired a permit!
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 6  to 7.
[Adder]Thread #0 is releasing Value's permit.
A thread has aquired a permit!
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 7  to 8.
[Adder]Thread #0 is releasing Value's permit.

その背後にある理由は何ですか?そして、可能であれば、それを修正する方法は?


追加情報:

この質問は、以前の並行性の質問の「続き」です。

新しいコードは、このセマフォチュートリアルに非常に基づいています。

4

1 に答える 1

4

問題は、独自のメソッドの同期です。Value.acquireとは両方ともValue.release同期されているため、-メソッドに入る1つのスレッドは、acquire別のスレッドによる呼び出しをブロックしますrelease。これは、release呼び出しがValue-classのモニターが解放されるのacquireを待機し、内部のスレッドが内部セマフォが取得されるのを待機するためです。synchronizedメソッドから-keywordsを削除すると、デッドロックの問題が解消されます。代わりに、おそらくget-、add-、および-subtractメソッドを同期することを意図していました。

于 2012-05-17T17:25:09.080 に答える