Java: When to use Interrupt vs flags?

Asked

Viewed 724 times

16

To indicate to a thread that it must "interrupt" its work Java provides a mechanism known as Interrupts:

public void run() {
    while(!Thread.interrupted()) {
        // Fazer algo
    }
}

// para interromper
minhaThread.interrupt();

That said, it is not uncommon to find code that does the same thing "on the nail" with a flag volatile:

private volatile boolean running = true;

public void stop() {
    running = false;
}

public void run() {
    while(running) {
        // Fazer algo
    }
}

// para interromper
minhaThread.stop();

When should I use each of these techniques?

4 answers

11


The use of a flag volatile, as presented in the question, it brings no benefit beyond a feeling on the part of the developer to have in his hands the "control" of execution. :)

Interruptions

The Java Threads API has implemented a generic use flag to manage "paused thread interrupts".

If a thread is paused in a call to Object#wait(), Thread#join or Thread#sleep, the method interrupt() is able to "wake her up". In practice, it is as if there had been an error in the call to one of these methods and he launched the exception InterruptedException.

Certain input and output (I/O) operations may also be affected, for example those using InterruptibleChannel.

The interrupt flag implementation is native, so the JVM can use more optimized mechanisms for communication between threads.

Therefore, if used correctly, the API provides advanced mechanisms to stop a thread from running even when there are time-consuming operations being performed, such as file access and networking.

Interruptions and ties

Such a flag is also commonly used to interrupt ties, as in the question example.

The only danger in doing this is not controlling the status of the interrupt flag properly.

For example, if you treat the interruption exception:

public void run() {
    while(!Thread.interrupted()) {
        // Começa algo
        try {
            // Faz algo que pode lançar InterruptedException
        } catch (InterruptedException e) {
            log.error(e);
        }
        // Finaliza algo
    }
}

The code above will result in a noose infinite because capturing the exception clears the flag and the output condition of the loop will always be false!

Because of this, if there is need to catch such exception, in general is recommended that the interruption in the catch, thus:

public void run() {
    while(!Thread.interrupted()) {
        // Começa algo
        try {
            // Faz algo que pode lançar InterruptedException
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error(e);
        }
        // Finaliza algo
    }
}

Since the exception treatment may be "hidden" within another method, some recommend, as a precaution, always calling the interrupt within a catch that captures such an exception.

Flag volatile

Manually controlling with a flag has some disadvantages, among which I consider the worst:

  • Variable sharing required. Threads need to communicate directly, increasing coupling.
  • Inability to interrupt queued threads.
  • Developers who don’t understand the volatile. Some try to imitate the use and forget the modifier, which can lead to racing conditions and unexpected behaviors.

On the other hand, there are advantages to this approach:

  • If the flag is not simply one boolean, that is, if there is any more complex object that is shared. For example, in the case of threads consuming a queue, the "flag" may be the queue is empty.
  • Whether an arbitrary number of threads depends on the same flag.
  • If no immediate interruption of the current thread iteration is desired. It may be, for example, that the goal is just to finish the loop, but any operation waiting for wait or join should continue until the end.
  • The use of a flag in such a trivial loop is simpler to understand, compared to the API.

API confusing

Unfortunately, the Java interrupt control API is somewhat confusing. Compare the methods available:

  • Thread.interrupt(): interrupts a thread. It should be called directly on an object, which can be the current thread (as in the example above) or some other thread, if you want to interrupt it. This method activates the interrupt flag.
  • Thread.isInterrupted(): checks if the interrupt flag is active for a given thread. It should also be called in an object, which may be the current thread or another thread.
  • Thread.interrupted(): returns the state of the interrupt flag and clears the flag. This is a static method of the class, so it is called without an object and always references the current thread.

The first two methods make a lot of sense, but the last one is somewhat strange, because once it is invoked it effectively clears the flag. this leads to unusual situations such as when a boolean expression is used in a if modifies the state and code below "see" other values.

Considerations

My suggestion is to use the API by default when this applies to the problem. If there is a more specific need, a manual solution is needed and there are no problems with this.

It’s not wrong to use a flag, but for a mature developer it’s important to learn how to use the Java API - or any language you use. Part of this is avoiding solutions ad hoc when possible.

  • 1

    Perfect as ever @utluiz. I’ll leave a Bounty ;).

  • O código acima vai resultar num laço infinito porque capturar a exceção limpa a flag!

Por causa disso, se houver necessidade de capturar tal exceção, em geral recomenda-se que se restaure a interrupção no catch, assim: All this is true, but your loop remains infinite if you don’t have one return in the catch

  • @Brunocosta Bruno, do not go because there is the condition no while. When the thread interrupts itself, in this case it restores the interrupt flag and will return true in the Interrupted method.

  • @utluiz Oops, it’s true...

  • There is also the isInterrupted() that does not clear the state of the flag. I never understood the reason for interrupted() be static... Meanwhile, inside a Runnable you need to call currentThread().isInterrupted() to access the variant that does not clear the flag. For me the option that does not clear the flag should be the default

  • utluiz, I swear I will not turn your answer into the endless and unnecessary debate ever... But already turning into the usual endless and unnecessary debate, the volatile would be unnecessary even if stop() is invoked from another Thread?

  • 1

    @Anthonyaccioly These interrupt methods are chaos. Then I will include a topic in the answer about this. About volatile, I didn’t mean that it’s unnecessary. I probably misexpressed myself at some point. I meant that the flag is unnecessary.

Show 2 more comments

5

Threads can go into standby mode and wait for a condition to continue. In the case of wait() this condition is a notify() or notifyAll(). In the case of a sleep() is simply that the time of "sleep" is elapsed.

Use interrupt() when you want to do the thread get out early in these modes of waiting, which will cause her to launch a InterruptedException.

On the other hand, use a flag the mechanism of interrupt() and check the interrupted status of thread when it is performing logical operations (it is not in standby mode) and you want it to end one of those operations and not continue the next ones. For example, if she is recording a list of files and you want her to stop when completing the recording of one of the files, without continuing to record the next ones.

Care should be taken with the method used to check the status of interrupted, because although the isInterrupted() does not clear flag status, other methods like interrupted() clean.

There is a use for the volatile in multithreading, but I confess that my knowledge is incomplete and I do not know why it is being used in this case. I believe it is not necessary in the scenario I described.

3

I understand that things are a little different!

To use interrupt it is necessary that within your method run throw a InterruptedException, so that when calling the interrupt this bid to Exception.

The cases that the InterruptedException must be implemented:

  1. java.lang.Object#wait()
  2. java.lang.Object#wait(long)
  3. java.lang.Object#wait(long, int)
  4. java.lang.Thread#sleep(long)

An example of how to stop a method run through the interrput :

public void run() {
        int pt = 0;
        try {
            while(true){
                System.out.println("ActionInterrupt {"+pt+"}");
                Thread.sleep(123L);
                pt++;
            }
        } catch (InterruptedException e) {
        // VAI CAIR AQUI, QUANDO CHAMAR O INTERRUPT!
            e.printStackTrace();
        }
    }

With the flag, there’s no need! It’s simpler and more direct!

I don’t need the Exception to stop the activity!

Completion:

If your Thread not launch a InterruptedException, then the flag should be used.

Follow an example!

  • 2

    Hi Thiago, but in addition to launching the InterruptedException if Thread is "waiting" on one of these methods it seems that there is another way to check the interrupt (as in my example). A call to interrupt() also modifies a state that can be read with isInterrupted() or the static method interrupted(). It seems to me that the Exception is complementary to the state of interruption... Ie, interrupt apparently does the same as the flag and something else, correct?

  • So the way to check the flag interruption would be to check its status: while(suaThread.running). So she should be volatile, for its value to be made available to all Threads in real time. If your Thread does not enter one of the 4 states cited, the method interrupted will always return false! Technically the interrupt will finish the sleep before expected, while the flag will respect the while. @Piovezan, gave a great explanation about this!

  • I think for the two forms to work equally, it depends on the implementation! If you let the try{ }cath within a while the isInterrupted will not update! Follow an example

  • 1

    Yeah, that’s my point. A InterruptedException is a Feature extra to handle threads in WAITING, TIMED_WAIT, etc. That said, it follows an example where the thread is interrupted without entering any of the above methods (just checking the method interrupted() returning true correctly after the call to interrupt()): Link to the example

  • 1

    @Anthonyaccioly I understand. In fact it is as you said, the mechanism of Interrupt dispenses with the use of the flag. I updated my answer accordingly.

1

My experience

  • Your project is simple.
  • Few threads
  • Few routines

So we can consider such a scenario as any well-implemented solution serves. Context, I participated in a project where parallel processing was the main requirement.

Any of these solutions adopted or proposed there does not meet.

  • First item high complexity
  • Big flags, tags and object states issues
  • It is very much up to you programmer to do the code (parallel processing control).
  • Second join 1, 2, 3, different frameworks, jsf, Quartz, Jbossseam and a Weblogic server for example.
  • Hibernate, transactions and IOC.
  • Little experience, lack of time, people walking everywhere, all lost.

This will never work.

Solution:

Use a thread pool controller:

  • Threadpoolexecutor (for example)
  • Master transactions
  • Parallel processing (which you can run in parallel)
  • Code blocks protected, synchronized (should not synchronize but have multiple instances, but sometimes this is not possible)
  • Complete control of transaction cycles
  • Complete IOC control (if used in the project)
  • If possible use thread pool of the framework itself, they are usually good.

In itself these are recommendations that serve for some project manager or analyst, even for programmers in general.

  • Well relevant to real projects, although it does not answer directly to what was asked.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.