java 如何在java中确保代码块不会被任何其他线程中断

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/337903/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:01:06  来源:igfitidea点击:

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

javamultithreadingsynchronizationthread-priority

提问by Jon Skeet

exampl:

例子:

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

      *code that must not be interrupted*

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

SomeOtherThread.start();

YetAntherThread.start();

How can you ensure that code that must not be interruptedwon't be interrupted?

如何确保不能被中断的代码不会被中断?

回答by Jon Skeet

You can't - at least not with normal Java, running on a normal, non-real-time operating system. Even if other threads don't interrupt yours, other processesmight well do so. Basically you won't be able to guarantee that you get a CPU all to yourself until you're done. If you want this sort of guarantee you should use something like Java Real-Time System. I don't know enough about it to know whether that would definitely provide the facility you want though.

你不能——至少不能用普通的 Java,在普通的非实时操作系统上运行。即使其他线程不中断您的线程,其他进程也可能会这样做。基本上,在完成之前,您将无法保证自己拥有 CPU。如果您想要这种保证,您应该使用 Java 实时系统之类的东西。我不太了解它,不知道这是否肯定会提供您想要的设施。

The bestthing to do is avoid that requirement in the first place.

最好做的事情是避免在首位这一要求。

回答by Chris Conway

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 ReadWriteLockand not simple object synchronization:

假设您只关心应用程序级线程争用,并假设您愿意按照其他人的建议大惊小怪(恕我直言,这是一个非常糟糕的主意),那么您应该使用一个ReadWriteLock而不是简单的对象同步:

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();

回答by james

Actually, you cando this if you control the thread instance you are running on. Obviously, there are a ton of caveats on this (like hanging io operations), but essentially you can subclass Thread and override the interrupt() method. you can then put some sort of boolean in place such that when you flip a flag, interrupt() calls on your thread are either ignored or better yet stored for later.

实际上,如果您控制正在运行的线程实例,则可以执行此操作。显然,对此有很多警告(例如挂起 io 操作),但基本上您可以子类化 Thread 并覆盖 interrupt() 方法。然后,您可以放置​​某种布尔值,这样当您翻转标志时,线程上的中断()调用要么被忽略,要么更好地存储以备后用。

回答by Bill K

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?

除非您运行实时 java.util.Date ,否则您无法停止垃圾收集等。那是你想要的吗?

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.

剩下的唯一一件事是:如果您只是希望所有其他 Java 线程不要相互中断,因为它们都倾向于在不受控制的情况下随意访问某些资源,那么您就错了。正确设计它,以便同步需要以同步方式访问的对象/数据,然后不要担心其他线程会中断您,因为您的同步对象是安全的。

Did I miss any possible cases?

我是否错过了任何可能的情况?

回答by OscarRyz

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

使用同步方法(以此处发布的各种形式)根本没有帮助。

That approach only helps to make sure that onethread 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 )

它只会使应用程序变慢一点,因为 JVM 必须执行额外的验证才能执行同步部分(仅由一个线程使用,因此浪费 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 ).

实际上,按照您的方式,线程并没有“真正”被中断。但似乎确实如此,因为它必须为其他线程提供 CPU 时间。线程的工作方式是;CPU 为每个线程提供了在很短的时间内运行一小会的机会。即使在单个线程运行时,该线程也会与其他应用程序的其他线程产生 CPU 时间(假设使用单处理器机器以保持讨论简单)。

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:

如果所有线程都具有相同的优先级,那么线程 1、2、3 的一个可能的调度可能是这样的:

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:

将 max 设置为 1,将 min 设置为 2,3,它可能是这样的:

More cpu to thread 1

更多的 CPU 到线程 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

一个线程要被另一个线程中断,它必须处于可中断状态,通过调用、Object.wait、Thread.join或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.

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

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

代码 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
    }
}

回答by R Hodges

Error processing is an example of a use case where it is very useful to stop threads from being interrupted. Say you have a large multi-threaded server and some external condition arises that causes errors to be detected on multiple worker threads simultaneously. Each worker thread generates a notification that an error occurred. Let's say further the desired response is to bring the server to a safe state that will allow it to restart after the error condition is cleared.

错误处理是一个用例,其中阻止线程被中断非常有用。假设您有一个大型多线程服务器,并且出现了一些导致在多个工作线程上同时检测到错误的外部条件。每个工作线程都会生成一个发生错误的通知。让我们进一步说,所需的响应是将服务器置于安全状态,以允许它在错误条件清除后重新启动。

One way to implement this behavior is to have a state machine for the server that processes state changes in total order. Once an error notification arrives, you put it into the state machine and let the state machine process it in toto without interruption. This is where you want to avoid interruptions--you want the first notification to cause the error handler to run. Further notifications should not interrupt or restart it. This sounds easy but really isn't--suppose the state machine was putting the server online. You wouldwant to interrupt that to let error processing run instead. So some things are interruptible but others are not.

实现此行为的一种方法是为服务器设置一个状态机,以全序处理状态更改。一旦错误通知到达,您就将其放入状态机中,让状态机不间断地处理它。这是您希望避免中断的地方——您希望第一个通知导致错误处理程序运行。进一步的通知不应中断或重新启动它。这听起来很简单,但实际上并非如此——假设状态机将服务器置于联机状态。您可能希望中断它以让错误处理运行。所以有些事情是可以中断的,但有些则不是。

If you interrupt the error processing thread it may blow the error handler out of the water during synchronized method processing, leaving objects in a potentially dirty state. This is the crux of the problem--thread interrupts go around the normal synchronization mechanism in Java.

如果您中断错误处理线程,它可能会在同步方法处理期间将错误处理程序吹出水面,使对象处于潜在的脏状态。这是问题的症结所在——线程中断绕过 Java 中的正常同步机制。

This situation is rare in normal applications. However, when it does arise the result can be byzantine failures that are very difficult to anticipate let alone cure. The answer is to protect such critical sections from interrupts.

这种情况在正常应用中很少见。然而,当它确实出现时,结果可能是拜占庭式的失败,很难预料,更不用说治愈了。答案是保护这些关键部分免受中断。

Java does not as far as I can tell give you a mechanism to stop a thread from being interrupted. Even if it did, you probably would not want to use it because the interrupt could easily occur in low-level libraries (e.g., TCP/IP socket processing) where the effect of turning off interrupts can be very unpredictable.

据我所知,Java 并没有提供一种机制来阻止线程被中断。即使这样做了,您也可能不想使用它,因为中断很容易发生在低级库(例如 TCP/IP 套接字处理)中,在这些库中关闭中断的效果是非常不可预测的。

Instead, it seems as if the best way to handle this is to design your application in such a way that such interrupts do not occur. I am the author of a small state machine package called Tungsten FSM (https://code.google.com/p/tungsten-fsm). FSM implements a simple finite-state machine that ensures events are processed in total order. I'm currently working on a bug fix that addresses exactly the problem described here. FSM will offer one way to address this problem but there are many others. I suspect most of them involve some sort of state machine and/or event queue.

相反,似乎处理此问题的最佳方法是以不发生此类中断的方式设计您的应用程序。我是一个名为 Tungsten FSM ( https://code.google.com/p/tungsten-fsm)的小型状态机包的作者。FSM 实现了一个简单的有限状态机,可确保按总顺序处理事件。我目前正在处理一个错误修复程序,该修复程序正好解决了此处描述的问题。FSM 将提供一种解决此问题的方法,但还有许多其他方法。我怀疑它们中的大多数都涉及某种状态机和/或事件队列。

If you take the approach of preventing interruptions it of course creates another problem if non-interruptible threads become blocked for some reason. At that point you are simply stuck and have to restart the process. It does not seem all that different from a deadlock between Java threads, which is in fact one way non-interruptible threads can become blocked. There's really no free lunch on these types of issues in Java.

如果您采取防止中断的方法,如果不可中断的线程由于某种原因被阻塞,它当然会产生另一个问题。在这一点上,您只是卡住了,必须重新启动该过程。这与 Java 线程之间的死锁似乎没有什么不同,这实际上是不可中断线程被阻塞的一种方式。关于 Java 中的这些类型的问题,真的没有免费的午餐。

I have spent a lot of time looking at problems like this--they are very difficult to diagnose let alone solve. Java does not really handle this kind of concurrency problem very well at all. It would be great to hear about better approaches.

我花了很多时间研究这样的问题——它们很难诊断,更不用说解决了。Java 并没有真正很好地处理这种并发问题。很高兴听到更好的方法。

回答by Yoni Roit

Before a thread is interrupted, security manager's checkAccess() method is called. Implement your own security manager, call System.setSecurityManager to install it and make sure it doesn't let any other thread interrupt you while it is in critical section.

在线程中断之前,调用安全管理器的 checkAccess() 方法。实现你自己的安全管理器,调用 System.setSecurityManager 来安装它并确保它在临界区时不会让任何其他线程中断你。

回答by Jesse Barnum

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();

回答by Perdi Estaquel

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();

回答by benez

A usual program does not randomly interrupt threads. So if you start a new Threadand you are not passing the reference to this Threadaround, you can be quite sure that nothing will interrupt that Thread.

通常的程序不会随机中断线程。所以如果你开始一个 newThread并且你没有传递对 this 的引用Thread,你可以非常确定没有任何东西会中断那个Thread

Keep the reference to the Threadprivate is sufficient in most scenarios. Everything else would be hacky.

Thread在大多数情况下,保持对私有的引用就足够了。其他一切都会变得很糟糕。

Typically work queues like ExecutorServicewill interrupt their Thread's when asked to do so. In these cases you want to deal with interrupts.

通常工作队列 likeExecutorServiceThread在被要求时中断他们的's 。在这些情况下,您希望处理中断。