Multi-threading is a very important knowledge point in Java. Here I will summarize Java Thread multi-threading for you. It is very useful. I hope you can master it.
1. Thread life cycle and five basic states
Regarding the life cycle of threads in Java, first take a look at the more classic picture below:
The above picture basically covers the important knowledge points of multi-threading in Java. After mastering each knowledge point in the above figure, you can basically master multi-threading in Java. Mainly include:
Java thread has five basic states
New state (New): When the thread object pair is created, it enters the new state, such as: Thread t = new MyThread();
Ready state (Runnable): When the start() method (t.start();) of the thread object is called, the thread enters the ready state. The thread in the ready state only means that the thread is ready and waiting for CPU scheduling execution at any time. It does not mean that the thread will be executed immediately after executing t.start();
Running status (Running): When the CPU starts to schedule the thread in the ready state, the thread can actually be executed at this time, that is, it enters the running state. Note: The ready state is the only entrance to the running state. That is to say, if a thread wants to enter the running state for execution, it must first be in the ready state;
Blocked state (Blocked): in the running state For some reason, the thread in the thread temporarily gives up the right to use the CPU and stops execution. At this time, it enters the blocking state. Until it enters the ready state, it has the opportunity to be called by the CPU again to enter the running state.
According to different reasons for blocking, the blocking state can be divided into three types:
1. Waiting for blocking: The thread in the running state executes the wait() method to cause this thread to Enter the waiting blocking state;
2. Synchronous blocking--if the thread fails to acquire the synchronized synchronization lock (because the lock is occupied by other threads), it will enter the synchronized blocking state;
3. Other blocking--When the thread's sleep() or join() is called or an I/O request is issued, the thread will enter the blocking state. When the sleep() state times out, join() waits for the thread to terminate or times out, or the I/O processing is completed, the thread re-enters the ready state.
Death state (Dead): The thread has finished executing or exited the run() method due to an exception, and the thread ends its life cycle.
2. Creation and startup of Java multi-threads
The creation of threads in Java is common in three basic forms
1.Inheritance Thread class, override the run() method of this class.
class MyThread extends Thread { private int i = ; @Override public void run() { for (i = ; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); } } } public class ThreadTest { public static void main(String[] args) { for (int i = ; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); if (i == ) { Thread myThread = new MyThread(); // 创建一个新的线程 myThread 此线程进入新建状态 Thread myThread = new MyThread(); // 创建一个新的线程 myThread 此线程进入新建状态 myThread.start(); // 调用start()方法使得线程进入就绪状态 myThread.start(); // 调用start()方法使得线程进入就绪状态 } } } }
As shown above, inherit the Thread class and define a new thread class MyThread by overriding the run() method. The method body of the run() method represents the task that the thread needs to complete, which is called Thread execution body. When this thread class object is created, a new thread is created and enters the thread new state. By calling the start() method referenced by the thread object, the thread enters the ready state. At this time, the thread may not be executed immediately, depending on the CPU scheduling timing.
2. Implement the Runnable interface and rewrite the run() method of the interface. The run() method is also a thread execution body. Create an instance of the Runnable implementation class and use this instance as a Thread The target of the class is used to create a Thread object, which is the real thread object.
class MyRunnable implements Runnable { private int i = ; @Override public void run() { for (i = ; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); } } } public class ThreadTest { public static void main(String[] args) { for (int i = ; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); if (i == ) { Runnable myRunnable = new MyRunnable(); // 创建一个Runnable实现类的对象 Thread thread = new Thread(myRunnable); // 将myRunnable作为Thread target创建新的线程 Thread thread = new Thread(myRunnable); thread.start(); // 调用start()方法使得线程进入就绪状态 thread.start(); } } } }
I believe that everyone is familiar with the above two ways of creating new threads, so what is the relationship between Thread and Runnable? Let's first look at the following example.
public class ThreadTest { public static void main(String[] args) { for (int i = ; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); if (i == ) { Runnable myRunnable = new MyRunnable(); Thread thread = new MyThread(myRunnable); thread.start(); } } } } class MyRunnable implements Runnable { private int i = ; @Override public void run() { System.out.println("in MyRunnable run"); for (i = ; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); } } } class MyThread extends Thread { private int i = ; public MyThread(Runnable runnable){ super(runnable); } @Override public void run() { System.out.println("in MyThread run"); for (i = ; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); } } }
Similarly, the method of creating a thread by implementing the Runnable interface is similar, but the difference is that
Thread thread = new MyThread(myRunnable);
Can this method successfully create a new thread? The answer is yes. As for the thread execution body at this time, is it the run() method in the MyRunnable interface or the run() method in the MyThread class? Through the output, we know that the thread execution body is the run() method in the MyThread class. In fact, the reason is very simple, because the Thread class itself also implements the Runnable interface, and the run() method was first defined in the Runnable interface.
public interface Runnable { public abstract void run(); }
Let’s take a look at the implementation of the run() method in the Runnable interface in the Thread class:
@Override public void run() { if (target != null) { target.run(); } }
In other words, when the run() method in the Thread class is executed, it will first Determine whether the target exists. If it exists, execute the run() method in the target, that is, the run() method in the class that implements the Runnable interface and overrides the run() method. However, in the example given above, due to the existence of polymorphism, the run() method in the Thread class is not executed at all, but the run() method in the runtime type, that is, the MyThread class, is directly executed first.
3. Use Callable and Future interfaces to create threads. Specifically, create an implementation class of the Callable interface and implement the clam() method. And use the FutureTask class to wrap the object of the Callable implementation class, and use this FutureTask object as the target of the Thread object to create a thread.
It seems a bit complicated, but it will become clear if you just look at an example.
public class ThreadTest { public static void main(String[] args) { Callable<Integer> myCallable = new MyCallable(); // 创建MyCallable对象 FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask来包装MyCallable对象 for (int i = ; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); if (i == ) { Thread thread = new Thread(ft); //FutureTask对象作为Thread对象的target创建新的线程 thread.start(); //线程进入到就绪状态 } } System.out.println("主线程for循环执行完毕.."); try { int sum = ft.get(); //取得新创建的新线程中的call()方法返回的结果 System.out.println("sum = " + sum); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } class MyCallable implements Callable<Integer> { private int i = ; // 与run()方法不同的是,call()方法具有返回值 @Override public Integer call() { int sum = ; for (; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); sum += i; } return sum; } }
首先,我们发现,在实现Callable接口中,此时不再是run()方法了,而是call()方法,此call()方法作为线程执行体,同时还具有返回值!在创建新的线程时,是通过FutureTask来包装MyCallable对象,同时作为了Thread对象的target。那么看下FutureTask类的定义:
public class FutureTask<V> implements RunnableFuture<V> { //.... } public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
于是,我们发现FutureTask类实际上是同时实现了Runnable和Future接口,由此才使得其具有Future和Runnable双重特性。通过Runnable特性,可以作为Thread对象的target,而Future特性,使得其可以取得新创建线程中的call()方法的返回值。
执行下此程序,我们发现sum = 4950永远都是最后输出的。而“主线程for循环执行完毕..”则很可能是在子线程循环中间输出。由CPU的线程调度机制,我们知道,“主线程for循环执行完毕..”的输出时机是没有任何问题的,那么为什么sum =4950会永远最后输出呢?
原因在于通过ft.get()方法获取子线程call()方法的返回值时,当子线程此方法还未执行完毕,ft.get()方法会一直阻塞,直到call()方法执行完毕才能取到返回值。
上述主要讲解了三种常见的线程创建方式,对于线程的启动而言,都是调用线程对象的start()方法,需要特别注意的是:不能对同一线程对象两次调用start()方法。
三. Java多线程的就绪、运行和死亡状态
就绪状态转换为运行状态:当此线程得到处理器资源;
运行状态转换为就绪状态:当此线程主动调用yield()方法或在运行过程中失去处理器资源。
运行状态转换为死亡状态:当此线程线程执行体执行完毕或发生了异常。
此处需要特别注意的是:当调用线程的yield()方法时,线程从运行状态转换为就绪状态,但接下来CPU调度就绪状态中的哪个线程具有一定的随机性,因此,可能会出现A线程调用了yield()方法后,接下来CPU仍然调度了A线程的情况。
由于实际的业务需要,常常会遇到需要在特定时机终止某一线程的运行,使其进入到死亡状态。目前最通用的做法是设置一boolean型的变量,当条件满足时,使线程执行体快速执行完毕。如:
public class ThreadTest { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); for (int i = ; i < ; i++) { System.out.println(Thread.currentThread().getName() + " " + i); if (i == ) { thread.start(); } if(i == ){ myRunnable.stopThread(); } } } } class MyRunnable implements Runnable { private boolean stop; @Override public void run() { for (int i = ; i < && !stop; i++) { System.out.println(Thread.currentThread().getName() + " " + i); } } public void stopThread() { this.stop = true; } }
以上所述是小编给大家介绍的Java Thread多线程全面解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对PHP中文网的支持!
更多Java Thread多线程全面解析相关文章请关注PHP中文网!