Java: When to use interrupt vs flags?

16

To indicate to a thread that it should "break" its work, Java provides a mechanism known as Interrupts :

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

// para interromper
minhaThread.interrupt();

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

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?

    
asked by anonymous 01.11.2016 / 15:37

4 answers

11

The use of a volatile flag, as presented in the question, brings no benefit other than a sensation on the part of the developer to have in their hands the "control" of execution. :)

Interruptions

The Java Threads API has implemented a generic usage flag to manage "paused" thread breaks.

If a thread is paused in a call to Object#wait() , Thread#join or Thread#sleep , the interrupt() is able to" wake "it. In practice, it is as if an error occurred in calling one of these methods and it throws the InterruptedException exception.

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

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

Therefore, if used correctly, the API provides advanced mechanisms for stopping the execution of a thread even when there are time-consuming operations being performed, such as file and network access.

Interruptions and loops

Such a flag is also commonly used to break links , as in the example question.

The only danger in doing this is not to control the state of the interrupt flag properly.

For example, if you handle the interrupt 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 an infinite loop because catching the exception clears the flag and the loop exit condition will always be false!

Because of this, if you need to catch such an exception, in general it is recommended that if you restore the interrupt in catch , like this:

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

As the exception handling may be "hidden" within another method, some cautiously recommend that you always call interrupt within a catch that captures such an exception.

Flag volatile

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

  • Variable sharing is required. Threads need to communicate directly, increasing the coupling.
  • Inability to interrupt waiting threads.
  • Developers who do not understand volatile . Some try to imitate the use and forget the modifier, which can lead to unexpected race conditions and behavior.

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

  • If the flag is not simply a 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 being empty.
  • If an arbitrary number of threads depends on the same flag.
  • If it is not desired that immediate interruption of the current iteration of the thread does not occur. It may be, for example, that the goal is just to end the loop, but any operation waiting for wait or join should continue until the end.
  • The use of a flag in a trivial loop as the issue is simpler to understand compared to the API.

Confused API

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

  • Thread.interrupt() : Stops 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 in case you want to interrupt it. This method activates the interrupt flag.
  • Thread.isInterrupted (): checks whether the interrupt flag is active for a given thread. It should also be called on 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 a bit strange, because once it is invoked it effectively clears the flag. this leads to unusual situations such as when a Boolean expression used in a if modifies the state and the following code "sees" 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 is no problem with this.

It is not wrong to use a flag, but for a mature developer it is important to learn how to use the Java API - or whatever language it uses. This is part of avoiding ad hoc solutions when possible.

    
04.11.2016 / 03:10
5

Threads can enter standby 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() it is simply that the sleep time is elapsed.

Use interrupt() when you want to make the thread exit earlier of these standby modes, which will cause it to throw a InterruptedException .

On the other hand, use a flag the interrupt() mechanism and check the interrupted status of the thread when it is executing logical operations (it is not in waiting) and you want it to finish one of these operations and do not continue the next ones. For example, if it is recording a list of files and you want it to stop when you complete the recording of one of the files, without continuing to record the next ones.

Attention should be paid to the method used to check the interrupted status, since while isInterrupted() does not clear flag status, other methods like interrupted() clear.

There is a use for 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.

    
01.11.2016 / 23:16
3

I understand that things are a little different!

To use interrupt it is necessary that within% run method throw a InterruptedException , so that when calling interrupt this throws Exception.

The cases that InterruptedException should be implemented:

  • java.lang.Object#wait()
  • java.lang.Object#wait(long)
  • java.lang.Object#wait(long, int)
  • java.lang.Thread#sleep(long)
  • An example of how to stop a method run through 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();
            }
        }
    

    Already with the flag, there is no need! it is simpler and more direct!

    I do not need Exception to stop the activity!

    Conclusion :

    If your Thread does not cast a InterruptedException , then the flag must be used.

    Here's an example!

        
    01.11.2016 / 20:12
    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
    • Large problems with flags, tags and object states
    • It depends a lot on you programmer to do the code (parallel processing control).
    • Second join the 1, 2, 3, different frameworks, jsf, Quartz, JbossSeam and a Weblogic server for example.
    • Hibernate, transactions, and IOC.
    • Little experience, lack of time, people tiptoeing everywhere, all lost.

    This will never work.

    Solution :

    Use a thread pool controller:

    • ThreadPoolExecutor (example)
    • Master transactions
    • Parallel processing (which can run in parallel)
    • Protected, synchronized blocks of code (you should not synchronize but have multiple instances, but sometimes this is not possible)
    • Complete control of transaction cycles
    • Full IOC control (if used in the project)
    • If possible use thread pool of the frameworks themselves, they are usually good.

    These are the recommendations for some project manager or analyst, even for programmers in general.

        
    09.11.2016 / 23:33