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

发布于 2024-07-09 10:18:48 字数 285 浏览 7 评论 0原文

示例:

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

      *code that must not be interrupted*

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

SomeOtherThread.start();

YetAntherThread.start();

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

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 interrupted won't be interrupted?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

云巢 2024-07-16 10:18:48

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

最好的办法就是从一开始就避免这种要求。

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 processes might 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.

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

狠疯拽 2024-07-16 10:18:48

假设您只关心应用程序级线程争用,并且假设您愿意按照其他人的建议对锁大惊小怪(恕我直言,这是一个非常糟糕的主意),那么您应该使用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();

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();
漫雪独思 2024-07-16 10:18:48

实际上,如果您控制正在运行的线程实例,您可以做到这一点。 显然,这方面有很多注意事项(例如挂起 io 操作),但本质上您可以子类化 Thread 并重写 Interrupt() 方法。 然后,您可以放置​​某种布尔值,这样当您翻转标志时,线程上的interrupt()调用要么被忽略,要么更好地存储以供以后使用。

Actually, you can do 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.

生生漫 2024-07-16 10:18:48

您确实需要留下更多信息。

除非在实时操作系统上运行,否则无法阻止其他系统进程的执行。 你是这个意思吗?

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

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

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

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?

安稳善良 2024-07-16 10:18:48

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

这种方法仅有助于确保一个线程一次执行关键部分,但这不是您想要的。 您需要防止线程被中断。

读/写锁似乎有帮助,但没有什么区别,因为没有其他线程尝试使用写锁。

它只会使应用程序变慢一点,因为 JVM 必须执行额外的验证来执行同步部分(仅由一个线程使用,因此浪费 CPU)

实际上,按照您的方式,线程不是“真的”被打断了。 但看起来确实如此,因为它必须将 CPU 时间让给其他线程。 线程的工作方式是; CPU 为每个线程提供了在很短的时间内运行一段时间的机会。 即使一个线程运行时,该线程也会与其他应用程序的其他线程一起使用 CPU 时间(为了使讨论简单,假设一台处理器机器)。

这可能就是您认为线程不时被暂停/中断的原因,因为系统让应用程序中的每个线程运行一段时间。

那么,你能做什么?

为了增加不被打扰的感觉,你可以做的一件事就是为你的线程分配更高的优先级,并降低其余线程的优先级。

如果所有线程都具有相同的优先级,则线程 1,2,3 的可能调度可能如下所示:

均匀分布

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

将 max 设置为 1,将 min 设置为 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
    }
}

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
    }
}
献世佛 2024-07-16 10:18:48

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

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.

謸气贵蔟 2024-07-16 10:18:48

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

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

如果中断错误处理线程,则可能会在同步方法处理期间将错误处理程序从水中吹出,从而使对象处于潜在的脏状态。 这就是问题的关键——线程中断绕过了Java中的正常同步机制。

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

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

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

如果您采取防止中断的方法,如果不可中断线程由于某种原因被阻塞,那么当然会产生另一个问题。 到那时,您就会陷入困境,必须重新启动该过程。 这看起来与 Java 线程之间的死锁没有什么不同,这实际上是不可中断线程被阻塞的一种方式。 对于 Java 中的此类问题,确实没有免费的午餐。

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

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 would want 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.

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.

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.

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.

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.

别闹i 2024-07-16 10:18:48

只需启动您自己的子线程,并确保中断调用永远不会过滤到它。

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

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();
淡紫姑娘! 2024-07-16 10:18:48

我认为你需要锁定中断标志。 像这样的东西怎么样(未测试):

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

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();
嘿咻 2024-07-16 10:18:48

最好的中途解决方案是同步某个公共对象上的所有线程,以便当您位于关键部分时没有其他线程可运行。

除此之外我认为这是不可能的。 我很好奇什么样的问题需要这种类型的解决方案?

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 ?

最冷一天 2024-07-16 10:18:48

通常的程序不会随机中断线程。 因此,如果您启动一个新的Thread并且没有传递对此Thread的引用,您可以非常确定没有任何东西会中断该Thread >。

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

通常,像 ExecutorService 这样的工作队列会在被要求时中断其线程。 在这些情况下,您需要处理中断。

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

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文