Create thread
There are two ways to create threads:
- Inherit Thread class
- Implement the Runnable interface
The Thread class implements the Runnable interface. The biggest limitation of creating threads by inheriting Thread classes is that multiple inheritance is not supported. So in order to support multiple inheritance, the Runnable interface should be implemented. The threads created in the two ways are the same at work, and there is no essential difference.
The first way is to inherit the Thread class and override the run() method:
public class Work extends Thread { @Override public void run() { System.out.println("Working..."); } } public class Run { public static void main(String[] args) { Work work = new Work(); work.start(); System.out.println("End!"); } }
Run result may be "End!" Output first. When multithreading is used, the run result is independent of the call order.
Calling the run() method is just a normal method call and does not start the thread. If the start() method is called more than once, an IllegalThreadStateException is thrown.
The second way is to implement the Runnable interface:
public class Work implements Runnable { @Override public void run() { System.out.println("Working..."); } } public class Run { public static void main(String[] args) { Thread t = new Thread(new Work()); t.start(); System.out.println("End!"); } }
This way is no different from the first one in operation. Its advantage lies in breaking through the limitation of single inheritance.
Some construction methods of Thread class:
Construction method | Explain |
---|---|
Thread() | Create a new thread |
Thread(String name) | Create a new thread and specify a name |
Thread(Runnable target) | Create a new thread with target as the running object |
Thread(Runnable target, String name) | Take target as the running object and specify the name |
Thread(ThreadGroup group, Runnable target) | target as run object and as a member of thread group |
Thread method
currentThread() method
The currentThread() method returns information about the thread being executed.
public class Run() { public static void main(String[] args) { System.out.println(Thread.currentThread().getName()); } }
The above code outputs "main" in the console, indicating that the method is called by a thread named main.
import static java.lang.System.out; public class Run { static class Work extends Thread { @Override public void run() { out.printf("%s Be called\n", currentThread().getName()); } } public static void main(String[] args) { Work t1 = new Work(), t2 = new Work(); t1.start(); t2.start(); } }
Running results of the above code:
Thread-0 Be called Thread-1 Be called Process finished with exit code 0
In the run() method, you can omit the Thread and call the currentThread() method directly.
isAlive() method
This method determines whether the current thread is active.
import static java.lang.System.out; public class Run { static class Work extends Thread { @Override public void run() { out.printf("In operation %s\n", isAlive()); } } public static void main(String[] args) throws Throwable { Work t = new Work(); out.printf("Before running: %s\n", t.isAlive()); t.start(); // Wait for the thread to finish running Thread.sleep(1000); out.printf("End of operation: %s\n", t.isAlive()); } }
Running results of the above code:
Before running: false Running true End of run: false Process finished with exit code 0
sleep() method
The sleep() method specifies the number of milliseconds for the current thread to sleep (pause), which does not release the lock.
Stop thread
interrupt() method
The interrupt() method does not stop the thread immediately, but marks a stop in the thread.
import static java.lang.System.out; public class StopThread { static class Work extends Thread { @Override public void run() { for (int i = 1; i <= 50000; i++) { out.printf("i = %d\n", i); } } } public static void main(String[] args) throws Throwable { Work work = new Work(); work.start(); Thread.sleep(200); work.interrupt(); out.println("Call interrupt!"); } }
Running results of the above code:
... i = 8190 i = 8191 i = 8192 Call interrupt! i = 8193 i = 8194 i = 8195 ...
After the interrupt() method call, the thread is still running.
To stop a thread using the interrupt() method, you need to determine the interrupt status in the thread. There are two methods:
- interrupted(): test whether the current thread is in an interrupted state. After execution, clear the state to false.
- isInterrupted(): the function is the same as above, but the status is not cleared.
import static java.lang.System.out; public class StopThread { static class Work extends Thread { @Override public void run() { for (int i = 1; i <= 50000; i++) { if (isInterrupted()) { out.println("Jump out of circulation!"); break; } out.printf("i = %d\n", i); } } } public static void main(String[] args) throws Throwable { Work work = new Work(); work.start(); Thread.sleep(200); work.interrupt(); out.println("Call interrupt!"); } }
Execution result of the above code:
... i = 8301 i = 8302 i = 8303 i = 8304 i = 8305 i = 8306 i = 8307 Call interrupt! //Out of the loop! Process finished with exit code 0
After calling the interrupt() method, the loop has exited. But this method just jumps out of the loop. If there is code outside the for loop, it will still execute.
Throw an exception to stop the thread
When the thread status is judged to be interrupted, an exception can be thrown and the post interrupt processing can be performed in the catch or finally block:
import static java.lang.System.out; public class StopThread { static class Work extends Thread { @Override public void run() { try { for (int i = 1; i <= 50000; i++) { if (isInterrupted()) { out.println("Interrupted!"); throw new InterruptedException("Throw an exception!"); } out.printf("i = %d\n", i); } out.println("for Loop end!"); } catch (InterruptedException e) { out.println(e.getMessage()); } } } public static void main(String[] args) throws Throwable { Work work = new Work(); work.start(); Thread.sleep(200); work.interrupt(); out.println("Call interrupt!"); } }
The above code puts the task to be executed by the thread into the try block. When it is judged to be in the interrupt state, the InterruptedException is thrown. If the lock needs to be released, it can be executed in the finally block.
You can also cooperate with return to stop the thread:
if (isInterrupted()) { return; }
Pause thread
Java provides suspend() and resume() methods to pause and resume threads, but these two methods are expired and obsolete.
When the suspend() method pauses a thread, the lock is not released. So using the suspend() method is prone to deadlock.
If you need to pause the thread, you can add a tag. If the tag indicates that the thread needs to pause, use wait() to enter the waiting state. If you need to resume, use notify() to wake up.
import static java.lang.System.out; public class StopThread { static class Work extends Thread { // Pause mark private boolean isSuspended = false; void pause() { isSuspended = true; } synchronized void wake() { isSuspended = false; // awaken this.notify(); out.println("Awaken!"); } @Override public void run() { synchronized (this) { try { for (int i = 1; i <= 5000; i++) { if (isInterrupted()) { return; } if (isSuspended) { out.println("Suspended!"); // wait for this.wait(); } out.printf("%s i = %d\n", getName(), i); } out.printf("%s end!\n", getName()); } catch (InterruptedException e) { out.println(e.getMessage()); } } } } public static void main(String[] args) throws Throwable { Work work = new Work(); work.start(); Thread.sleep(100); // suspend work.pause(); Thread.sleep(100); // awaken work.wake(); } }
The above code uses wait() and notify() to suspend and resume threads. Operation result:
... Thread-0 i = 202 Thread-0 i = 203 Thread-0 i = 204 //Suspended! //Wake up! Thread-0 i = 205 Thread-0 i = 206 Thread-0 i = 207 ... Thread-0 i = 4998 Thread-0 i = 4999 Thread-0 i = 5000 Thread-0 end! Process finished with exit code 0
yield method
The yield() method is used to give up the current CPU resources and let other tasks take up CPU execution time. But the time of giving up is uncertain. It is possible to just give up and get time slice right away.
import static java.lang.System.currentTimeMillis; import static java.lang.System.out; public class Yield { static class Work extends Thread { @Override public void run() { long before = currentTimeMillis(); int sum = 0; for (int i =1; i < 2000000; i++) { // yield(); sum += (i + 1); } long after = currentTimeMillis(); out.printf("Cost: %dms\n", after - before); } } public static void main(String[] args) { new Work().start(); } }
When the above code does not use the yield() method, it will be executed in about 15 ms, plus about 500 ms.