Principle introduction:
Use interrupt to notify, not force
Best practice: how to stop threads correctly
- Normal stopping process (without external interference)
- The run() method has been executed
- There was an exception, but it was not caught
- Correct method: use interrupt to request to stop the thread
- Normal situation (there is no standard way to write sleep or wait methods in the run method)
- The thread may be blocked
- If the thread blocks after each work iteration (call the sleep method, etc.)
- If you don't write this, you will encounter a problem: the thread can't stop
- The problem of try/catch in while: the idea of java language when designing sleep function is to clear the interrupt flag bit in case of interrupt
public static void main(String[] args) throws InterruptedException { Runnable runnable = () -> { int num = 0; while (num <= 10000 && !Thread.currentThread().isInterrupted()) { try { if (num % 100 == 0) { System.out.println(num + "Is a multiple of 100"); } num++; Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread thread = new Thread(runnable); thread.start(); Thread.sleep(5000); thread.interrupt(); }
- Coding habits to pay attention to in actual production development
- Two best treatment methods
- Priority: pass interrupt, direct throw exception
- Undesired or undeliverable: resume interrupt through Thread.currentThread().interrupt();
- Interrupts should not be masked
- Two best treatment methods
- Summary of a list of common methods that can throw interruptedexceptions in response to interrupts
- Object.wait()/wait(long)/wait(long,int)
- Thread.sleep(long)/sleep(long,int)
- Thread.join()/join(long)/join(long,int)
- java.util.concurrent.BlockingQueue.take()/put(E)
- java.util.concurrent.locks.Lock.lockInterruptibly()
- java.util.concurrent.CountDownLatch.await()
- java.util.concurrent.Exchanger.exchange(V)
- java.util.concurrent.CyclicBarrier.await()
- java.nio.channels.InterruptibleChannel related methods
- Related methods of java.nio.channels.Selector
Wrong stop method
- Deprecated stop, suspend, and resume methods
- Consequences of using stop
- Using stop() to stop a thread will cause the thread to stop suddenly in the middle of its operation. It is impossible to complete the operation of a basic unit (a company), which will cause dirty data (some companies will receive more equipment and less equipment)
- Error theory about stop
- Using stop cannot release the lock, which is wrong
- suspend questions
- suspend suspends the thread, but does not release resources such as locks. Over time, it will cause deadlock
- Resume: resume the thread. It will not work if the thread has not been suspend ed before.
- Consequences of using stop
- Set Boolean flag bit with volatile
- It seems feasible
- Mistakes
- It's blocked. I didn't check it
- Correction method
- It is solved by the interrupt method, not volatile
- Demonstrate volatile failure mode
/** * Demonstrate the limitations of volatile part2: volatile cannot stop a thread when it is blocked * In this example, the production speed of producers is fast and the consumption speed of consumers is slow * Therefore, when the blocking queue is full, producers will block and wait for consumers to consume further */ public class WrongWayVolatileCantStop { public static void main(String[] args) throws InterruptedException { ArrayBlockingQueue<Object> storage = new ArrayBlockingQueue<>(10); Producer producer = new Producer(storage); Thread thread = new Thread(producer); thread.start(); Thread.sleep(1000); Consumer consumer = new Consumer(storage); while (consumer.needMoreNums()) { System.out.println(consumer.storage.take() + "Consumed"); Thread.sleep(100); } System.out.println("Consumers don't need more data..."); // Once consumers don't need more data, producers should stop producer.canceled = true; } } class Producer implements Runnable { BlockingQueue storage; public volatile boolean canceled = false; public Producer(BlockingQueue storage) { this.storage = storage; } @Override public void run() { int num = 0; try { while (num <= 100000 && !canceled) { if (num % 100 == 0) { storage.put(num); System.out.println(num + "Is a multiple of 100."); } num++; } } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("Producer end run"); } } } class Consumer { BlockingQueue storage; public Consumer(BlockingQueue storage) { this.storage = storage; } public boolean needMoreNums() { return Math.random() <= 0.95; } }
Analysis of important functions related to stopping threads
- Interrupt thread
- Principle analysis of interrupt method
- Determine whether it has been interrupted
- static boolean interrupted()
- boolean isInterrupted()
- For example, note that the target object of Thread.interrupted() is "current thread",
Common interview questions
- How to stop a thread
- Principle: use interrupt to request and benefit
- To stop a thread, the requestor, the stopped party, and the sub method callee should cooperate with each other
- Finally, the wrong method: stop/suspend is obsolete, and volatile's Boolean method cannot handle long-term blocking
- If you deal with non interruptible blocking (for example, ReentrantLock.lock() or Socket I/O fails to respond to interrupts, how should you stop the thread?)