How can you ensure in java that a block of code can not be interrupted by any other thread

前端 未结 11 1490
灰色年华
灰色年华 2021-01-04 10:02

exampl:

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

      *code that must not be interrupted*

      *some more code*
    }
  }         


        
相关标签:
11条回答
  • 2021-01-04 10:40

    You really need to leave more info.

    You cannot stop other system processes from executing unless you run on a real-time OS. Is that what you mean?

    You cannot stop garbage collection, etc unless you run a real-time java. Is that what you wanted?

    The only thing left is: If you simply want all YOUR other java threads to not interrupt each other because they all tend to access some resource willy-nilly without control, you are doing it wrong. Design it correctly so that objects/data that NEED to be accessed in a synchronized manner are synchronized then don't worry about other threads interrupting you because your synchronized objects are safe.

    Did I miss any possible cases?

    0 讨论(0)
  • 2021-01-04 10:42

    I think you need to lock on an interrupt flag. What about something like this (not tested):

    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();
    
    0 讨论(0)
  • 2021-01-04 10:44

    Using the synchronized approach ( in the various forms posted here ) doesn't help at all.

    That approach only helps to make sure that one thread executes the critical section at a time, but this is not what you want. You need to to prevent the thread from being interrupted.

    The read/write lock seems to help, but makes no difference since no other thread is attempting to use the write lock.

    It only makes the application a little slower because the JVM has to perform extra validations to execute the synchronized section ( used only by one thread , thus a waste of CPU )

    Actually in the way you have it, the thread is not "really" being interrupted. But it seems like it does, because it has to yield CPU time to other threads. The way threads works is; the CPU gives to each thread a chance to run for a little while for very shorts periods of time. Even one when a single thread running, that thread is yielding CPU time with other threads of other applications ( Assuming a single processor machine to keep the discussion simple ).

    That's probably the reason it seems to you like the thread is being paused/interrupted from time to time, because the system is letting each thread in the app run for a little while.

    So, what can you do?

    To increase the perception of no interruptions, one thing you can do is assign a higher priority to your thread and decrease it for the rest.

    If all the threads have the same priority one possible schedule of threads 1,2,3 could be like this:

    evenly distributed

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

    While setting max for 1, and min for 2,3 it could be like this:

    More cpu to thread 1

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

    For a thread to be interrupted by another thread, it has to be in an interruptable state, achieved by calling, Object.wait, Thread.join, or Thread.sleep

    Below some amusing code to experiment.


    Code 1: Test how to change the priority of the threads. See the patterns on the ouput.

    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.
        }
    }
    

    Code 2. Sample of how can be a thread actually be interrupted ( while sleeping in this case )

    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
        }
    }
    
    0 讨论(0)
  • 2021-01-04 10:44

    Best halfway solution would be to synchronize all threads on some common object so that no other threads are runnable while you're in the critical section.

    Other than that I do not think it's possible. And I'm quite curious as to what kind of problem that requires this type of solution ?

    0 讨论(0)
  • 2021-01-04 10:46

    Assuming you're only concerned with application-level thread contention, and assuming you are willing to fuss with locks as suggested by others (which, IMHO, is a really bad idea), then you should use a ReadWriteLock and not simple object synchronization:

    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();
    
    0 讨论(0)
  • 2021-01-04 10:50

    Just start your own sub-thread, and make sure that the interrupt calls never filter through to it.

    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();
    
    0 讨论(0)
提交回复
热议问题