你怎么能在Java确保代码块不能被其他线程中断

问题描述 投票:11回答:11

例:

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

      *code that must not be interrupted*

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

SomeOtherThread.start();

YetAntherThread.start();

你怎么能保证不能中断不会被中断的代码?

java multithreading synchronization thread-priority
11个回答
14
投票

你不能 - 至少不是正常的Java,一个正常的,非实时操作系统上运行。即使其他线程不打断你的,其他进程很可能这样做。基本上你将不能够保证你得到一个CPU都以自己,直到大功告成。如果你想这种保证的,你应该使用类似Java的实时系统。我不知道有足够的了解才知道这是否肯定会提供你想要的,虽然设施。

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


0
投票

刚开始你自己的子线程,并确保中断通话从来没有经历过滤镜。

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
投票

的通常程序不随意中断线程。所以如果你开始一个新的Thread和你没有通过参照本Thread周围,你可以肯定什么都不会中断该Thread

保持参照Thread私人是在大多数情况下足够了。一切将是哈克。

通常工作队列像当问及这样做ExecutorService会打断他们Thread的。在这种情况下,你要处理的中断。


3
投票

其实,你可以做到这一点,如果你控制你正在运行的线程实例。显然,有这个(如挂的IO操作),但本质上你也可以继承线程和覆盖中断()方法一吨需要注意的地方。然后你可以把某种布尔到位,这样当你翻转标志,中断()调用你的线程被忽略或者更好的是存储供以后使用。


3
投票

你真的需要留出更多的信息。

您不能从运行,除非你在一个实时操作系统停止运行其他系统进程。你是这个意思吗?

除非你运行一个Java实时你不能阻止垃圾回收等。这是你想要的吗?

剩下的唯一的事情是:如果你只是想所有其他Java线程不打断对方,因为他们都倾向于无可奈何地访问某些资源没有控制,你就错了。正确地设计它,这样的对象/需要以同步的方式来访问是同步的数据,然后不用担心其它线程打断你,因为你的同步对象是安全的。

我错过任何可能的情况?


3
投票

使用同步的方法(在各种形式张贴在这里)没有帮助的。

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

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

它仅使应用程序慢一点,因为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

虽然设置最长为1,并分2,3-它可能是这样的:

更多的CPU线程1

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

3
投票

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

2
投票

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


2
投票

错误处理是一个用例,其中它是从被中断停止线程非常有用的一个例子。假设你有一个大的多线程服务器和一些外部条件发生导致的错误被同时对多个工作线程检测。每个工作线程产生一个错误发生的通知。比方说,进一步期望的反应是把服务器的安全状态,将允许误差条件被清除后,重新启动。

要实现此行为的一种方法是有一个状态机用于处理在总订单状态更改服务器。一旦错误通知到来时,你把它纳入国家机器,并让状态机处理其全盘没有中断。这是要避免干扰 - 你要第一个通知,导致错误处理程序运行。进一步的通知不应该中断或重新启动它。这听起来很容易,但真正isn't - 假设状态机是把服务器联机。你想中断一个让运行错误处理来代替。所以,有些事情是中断的,但有些不是。

如果中断错误处理线程可以同步的方法处理过程中吹错误处理出来的水,留下对象在潜在的脏状态。这就是问题的症结所在 - 线程中断四处Java中的正常的同步机制。

这种情况在正常的应用程序少见。然而,当它产生的结果可能是拜占庭故障是很难预料更不用说治愈。答案是保护这些关键部分出现中断。

Java没有,据我可以告诉给你一个机制被中断停止一个线程。即使这样,您可能不希望因为中断很容易出现在低级别的库(例如,TCP / IP套接字处理),使用它在那里关闭中断的影响可能是非常难以预测的。

相反,它好像来处理这个最好的办法就是以这样的方式不发生这样的中断来设计应用程序。我是一个小的状态机包称为钨FSM(https://code.google.com/p/tungsten-fsm)的作者。 FSM实现简单的有限状态机,以确保事件在总顺序进行处理。我目前工作的一个bug修复,解决正是这里所描述的问题。 FSM将提供解决这一问题的一种方式,但也有许多人。我怀疑其中大部分都涉及某种状态机和/或事件队列。

如果你把防止打扰它当然的方法创造了另一个问题,如果非中断线程被阻塞出于某种原因。在这一点上,你只是卡住,必须重新启动该进程。它似乎并没有从Java线程之间的僵局,这实际上是一种方式不可中断的线程会被阻塞所有不同。这确实对这些类型的Java的问题,没有免费的午餐。

我花了很多时间在看这样的问题 - 他们是非常难以诊断,更不用说解决。 Java并没有真正处理这类并发问题的很好的。这将是伟大听到更好的方法。


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

0
投票

中途最好的解决办法是这样,当你在关键部分是在没有其他线程运行的所有线程上的一些常见的对象同步。

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

© www.soinside.com 2019 - 2024. All rights reserved.