12

例:

new Thread(new Runnable() {
  public void run() {
    while(condition) {

      *code that must not be interrupted*

      *some more code*
    }
  }
}).start();

SomeOtherThread.start();

YetAntherThread.start();

中断してはいけないコードが中断されないようにするにはどうすればよいでしょうか?

4

11 に答える 11

14

できません。少なくとも、通常の非リアルタイム オペレーティング システムで実行されている通常の Java ではできません。他のスレッドがあなたのスレッドを中断しない場合でも、他のプロセスが中断する可能性があります。基本的に、完了するまで CPU を独り占めできるという保証はできません。この種の保証が必要な場合は、Java Real-Time System などを使用する必要があります。それがあなたが望む機能を確実に提供するかどうかを知るには、私はそれについて十分に知りません.

最善の方法は、そもそもその要件を回避することです。

于 2008-12-03T17:17:34.933 に答える
4

アプリケーションレベルのスレッドの競合のみに関心があると仮定し、他の人が提案したようにロックに大騒ぎすることをいとわないと仮定すると(これは本当に悪い考えReadWriteLockです)、単純なオブジェクト同期ではなくa を使用する必要があります。

import java.java.util.concurrent.locks.*;

// create a fair read/write lock
final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);

// the main thread grabs the write lock to exclude other threads
final Lock writeLock = rwLock.writeLock();

// All other threads hold the read lock whenever they do 
// *anything* to make sure the writer is exclusive when 
// it is running. NOTE: the other threads must also 
// occasionally *drop* the lock so the writer has a chance 
// to run!
final Lock readLock = rwLock.readLock();

new Thread(new Runnable() {
  public void run() {
    while(condition) {

      writeLock.lock();
      try {
        *code that must not be interrupted*
      } finally {
        writeLock.unlock();
      }

      *some more code*
    }
  }
}).start();

new SomeOtherThread(readLock).start();
new YetAntherThread(readLock).start();
于 2008-12-03T17:32:16.107 に答える
3

同期アプローチ (ここに掲載されているさまざまな形式) を使用しても、まったく役に立ちません。

このアプローチは、一度に1 つのスレッドがクリティカル セクション実行することを確認するのに役立ちますが、これは望ましいことではありません。スレッドが中断されないようにする必要があります。

読み取り/書き込みロックは役に立ちますが、他のスレッドが書き込みロックを使用しようとしないため、違いはありません。

JVM は同期セクションを実行するために追加の検証を実行する必要があるため、アプリケーションが少し遅くなるだけです (1 つのスレッドでのみ使用されるため、CPU が無駄になります)。

実際、あなたのやり方では、スレッドは「本当に」中断されていません。しかし、CPU 時間を他のスレッドに明け渡さなければならないので、そうなっているように見えます。スレッドの仕組みは次のとおりです。CPU は、各スレッドに非常に短い時間の間、実行する機会を与えます。単一のスレッドが実行されている場合でも、そのスレッドは他のアプリケーションの他のスレッドで CPU 時間を生み出しています (説明を簡単にするために単一のプロセッサ マシンを想定しています)。

システムがアプリ内の各スレッドを少しの間実行させているため、スレッドが時々一時停止/中断されているように見えるのはおそらくそれが理由です。

それで、あなたは何ができますか?

中断がないという認識を高めるためにできることの 1 つは、スレッドにより高い優先度を割り当て、残りの優先度を下げることです。

すべてのスレッドの優先度が同じ場合、スレッド 1、2、3 の可能なスケジュールの 1 つは次のようになります。

均等に分散

1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3

最大値を 1 に、最小値を 2.3 に設定すると、次のようになります。

スレッド 1 の CPU を増やす

1,1,1,2,1,1,3,1,1,1,2,1,1,1,3,1,2,1,1,1

スレッドが別のスレッドによって中断されるには、Object.wait、Thread.join、または Thread.sleep を呼び出すことによって達成される、中断可能な状態である必要があります。

実験するいくつかの面白いコードの下に。


コード 1: スレッドの優先度を変更する方法をテストします。出力のパターンを参照してください。

public class Test {
    public static void main( String [] args ) throws InterruptedException {
        Thread one = new Thread(){
            public void run(){
                while ( true ) {
                    System.out.println("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
                }
            }
        };
        Thread two = new Thread(){
            public void run(){
                while ( true ) {
                    System.out.println(".............................................");
                }
            }
        };
        Thread three = new Thread(){
            public void run(){
                while ( true ) {
                    System.out.println("------------------------------------------");
                }
            }
        };

        // Try uncommenting this one by one and see the difference.

        //one.setPriority( Thread.MAX_PRIORITY );
        //two.setPriority( Thread.MIN_PRIORITY );
        //three.setPriority( Thread.MIN_PRIORITY );
        one.start();
        two.start();
        three.start();

        // The code below makes no difference
        // because "one" is not interruptable
        Thread.sleep( 10000 ); // This is the "main" thread, letting the others thread run for aprox 10 secs.
        one.interrupt();  // Nice try though.
    }
}

コード 2. スレッドが実際に中断される方法のサンプル (この場合はスリープ中に)

public class X{
    public static void main( String [] args ) throws InterruptedException  {
        Thread a = new Thread(){ 

            public void run(){ 

                int i = 1 ; 
                while ( true ){ 
                    if ( i++ % 100 == 0 ) try {
                        System.out.println("Sleeping...");
                        Thread.sleep(500);
                    } catch ( InterruptedException ie ) {
                        System.out.println( "I was interrpted from my sleep. We all shall die!! " );
                        System.exit(0);
                    }
                    System.out.print("E,"); 
                }
            }

         };
        a.start();


        Thread.sleep( 3000 ); // Main thread letting run "a" for 3 secs. 
        a.interrupt(); // It will succeed only if the thread is in an interruptable state
    }
}
于 2008-12-03T21:09:59.787 に答える
3

あなたは本当にもっと多くの情報を残す必要があります.

リアルタイム OS で実行しない限り、他のシステム プロセスの実行を停止することはできません。そうですか?

リアルタイム Java を実行しない限り、ガベージ コレクションなどを停止することはできません。それはあなたが望んでいたものですか?

残っている唯一のことは次のとおりです。他のすべてのJavaスレッドが制御なしでリソースに勝手にアクセスする傾向があるため、他のすべてのJavaスレッドが相互に割り込まないようにしたい場合は、間違っています。同期された方法でアクセスする必要があるオブジェクト/データが同期されるように正しく設計し、同期されたオブジェクトが安全であるため、他のスレッドが中断することを心配しないでください。

考えられるケースを見逃しましたか?

于 2008-12-03T18:11:39.990 に答える
3

実際、実行中のスレッド インスタンスを制御すると、これを行うことができます。明らかに、これには多くの注意事項があります (io 操作のハングなど) が、基本的には Thread をサブクラス化し、interrupt() メソッドをオーバーライドできます。次に、フラグを反転すると、スレッドでの interrupt() 呼び出しが無視されるか、後で使用できるように保存されるように、何らかのブール値を配置できます。

于 2008-12-03T17:34:52.030 に答える
2

スレッドが中断される前に、セキュリティマネージャのcheckAccess()メソッドが呼び出されます。独自のセキュリティマネージャーを実装し、System.setSecurityManagerを呼び出してインストールし、クリティカルセクションにあるときに他のスレッドが邪魔しないようにします。

于 2008-12-03T18:14:27.567 に答える
1

独自のサブスレッドを開始するだけで、割り込み呼び出しがそれを通過しないことを確認してください。

new Thread(new Runnable() {
  public void run() {
    Thread t = new Thread() {
      public void run() {
        *code that must not be interrupted*
      }
    }
    t.start(); //Nothing else holds a reference to t, so nothing call call interrupt() on it, except for your own code inside t, or malicious code that gets a list of every live thread and interrupts it.

      while( t.isAlive() ) {
        try {
          t.join();
        } catch( InterruptedException e ) {
          //Nope, I'm busy.
        }
      }

      *some more code*
    }
  }
}).start();

SomeOtherThread.start();

YetAntherThread.start();
于 2014-01-11T21:44:19.317 に答える
1

割り込みフラグをロックする必要があると思います。このようなものはどうですか(テストされていません):

new Thread() {
    boolean[] allowInterrupts = { true };

    @Override
    public void run() {
        while(condition) {
            allowInterrupts[0] = false;
            *code that must not be interrupted*
            allowInterrupts[0] = true;
            *some more code*
        }
    }

    @Override
    public void interrupt() {
        synchronized (allowInterrupts) {
            if (allowInterrupts[0]) {
                super.interrupt();
            }
        }
    }
}.start();

SomeOtherThread.start();

YetAntherThread.start();
于 2014-10-06T22:51:27.133 に答える
0

最善の中間的な解決策は、クリティカルセクションにいる間は他のスレッドが実行できないように、いくつかの共通オブジェクトのすべてのスレッドを同期することです。

それ以外はありえないと思います。そして、この種の解決策を必要とする問題の種類について、私は非常に興味がありますか?

于 2008-12-03T17:09:17.870 に答える
-1

通常のプログラムでは、ランダムにスレッドに割り込むことはありません。したがって、 new を開始し、Threadthis への参照を渡していない場合Thread、それを中断するものは何もないことを確信できますThread

Threadほとんどのシナリオでは、プライベートへの参照を保持するだけで十分です。他のすべてはハックです。

通常、 のようなワーク キューは、要求されたときにExecutorServiceを中断しThreadます。このような場合、割り込みを処理する必要があります。

于 2018-11-05T20:17:22.833 に答える