Java Multithreading High Concurrency Basics (3) - Thread Life Cycle and Basic Operation Examples

Before talking about threads, it is necessary to talk about the relationship between threads and processes.

Attached to oracle official website link: https://docs.oracle.com/javase/tutorial/essential/concurrency/procthread.html

Here is the original introduction to threads and processes, we only briefly introduce them as knowledge popularization.

1. The relationship between processes and threads

1. Process: Process is generally synonymous with program or application, the basic unit of system resource and scheduling, and the basis of operating system structure. It has its own independent memory space, in other words, it has a private set of runtime resources. In modern thread-oriented computer architecture, processes exist as containers for threads , and processes become synonymous with programs. Note, however, that most implementations of the Java Virtual Machine run as a process.

2. Threads: In thread-oriented computer architecture, threads are sometimes referred to as lightweight processes. In a process, various threads share the resources (memory and files) of the process. Every application contains at least one thread.

 

3. Why use threads for concurrent programming?

Because relative to the process, the cost of thread switching and scheduling is far less than the process.

 

2. Thread life cycle

Since we want to talk about threads, it is inevitable to talk about the life cycle of threads, that is, the transition between various states.



 



 It can be seen that an enumeration type State is defined in the source code Thread class, which is the various states in the thread life cycle.

According to the English comments, we can know the meaning of each state, which will not be elaborated here.

The state transition diagram of the attached thread:

In the following chapters, we will gradually introduce the transition process between these states in detail.

 


 3. Basic operations of threads (these are very simple and will not be described in detail here)

1. Create a new thread

There are two ways to create a new thread: one is to inherit the Thread class and override the run method of the Thread class (because you need to implement your business logic in the run method); the other is to implement the Runnable interface.

 

public class ThreadDemo extends Thread {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		System.out.println("Inherit Thread to implement thread execution");
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new ThreadDemo().start();
	}

}
 

 

public class RunnableDemo implements Runnable {

	@Override
	public void run() {
		System.out.println("My first thread program!");
	}

	public static void main(String[] args) {
		new Thread(new RunnableDemo()).start();
	}

}
 In fact, looking at the source code, it is actually a way to directly implement the Runnable interface. We can look at the Thread source class:  so the discussion about how to create a new thread can be stopped. 2. Abandonment method (you can ignore it) stop method: violent termination, there will be data inconsistency, and it is reasonable to abandon it, and it is replaced by a method with an interrupt mechanism. suspend: The suspend method is also abandoned, because after calling this method, the thread will not release resources after suspending, and the state of the thread is RUNNABLE, which may make us misjudge the current system state.  resume: It is used in conjunction with suspend, but if it is executed before suspend, the thread will hang forever, and the picture will not be cut. 3. Interrupt method: There are three methods related to interruption: ①The interrupt() method in the Thread class is an instance method, which can set the interrupt flag of the thread (that is to say, it is not interrupted by calling this method) ②Cooperating with the method in the Thread class The instance method isInterrupted() is used to determine whether the current calling thread has set the interrupt flag. ③The interrupted() in the Thread class is also used to judge the current interrupt status, but it will clear the interrupt flag bit .
public static void main(String[] args) throws InterruptedException {
		Thread t = new Thread(){
			@Override
			public void run() {
				while(true){
		System.out.println(Thread.currentThread().interrupted());
					if(Thread.currentThread().isInterrupted()){
						System.out.println("I was interrupted!");
						break;
					}
				}
			}
		};
		t.start();
		t.interrupt();
	}
 In addition, it should be noted that when using the Thread.sleep(long xx) method (and the join method, any method that reports an interrupt exception), if the thread is interrupted, an interrupt exception will be thrown, and the flag will be cleared.
public static void main(String[] args) throws InterruptedException {
		Thread t = new Thread(){
			@Override
			public void run() {
				while(true){
					try {
						System.out.println(Thread.currentThread().getName()+"|"+Thread.currentThread().isInterrupted());
						Thread.sleep(1000);
						System.out.println(Thread.currentThread().getName()+"|"+Thread.currentThread().isInterrupted());
					} catch (InterruptedException e) {
						e.printStackTrace ();
						//If you want to handle the logic correctly, you need to restore the interrupt flag here and re-interrupt
						// reset the interrupt flag
						Thread.currentThread().interrupt();
					}
					if(Thread.currentThread().isInterrupted()){
						System.out.println("I was interrupted!");
						break;
					}
				}
			}
		};
		t.start();
		t.interrupt();
	}
  4. Wait (wait) and notification (notify) First of all, you must know that these two methods are methods in the Object class, which means that any class inherits these two methods. In a thread, when an object calls the wait() method, the current thread waits on this object. Wait until another thread calls the obj.notify() method. The first point to note, the object here is the same! Second, this object must be used as a monitor lock! The third point is that the waiting thread must obtain the monitor lock before it can be executed. It does not mean that another thread can be woken up after executing the notify() method!  
public class WaitNotifyDemo{
	final static Object obj = new Object();
	static class T1  extends Thread {
		@Override
		public void run() {
			synchronized (obj) {
				System.out.println(System.currentTimeMillis()+":T1 start!");
				try {
					obj.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace ();
				}
				System.out.println(System.currentTimeMillis()+":T1 end!");
			}
		}
	}
	static class T2  extends Thread {
		@Override
		public void run() {
			synchronized (obj) {
				System.out.println(System.currentTimeMillis()+":T2 start!");
				obj.notify();
				try {
					Thread.sleep(2000);//In order to see clearly, wait for 2s
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace ();
				}
				System.out.println(System.currentTimeMillis()+":T2 end!");
			}
		}
	}
	public static void main(String[] args) {
		new T1().start();
		new T2().start();
	}

}
   5. Thread joining (join) and yield (yield) Thread joining: If the join() method of thread B is called in a thread A, then thread A must wait for the logic execution of thread B to complete before continuing to execute. own A's logic. Joining actually means walking together! In the following example, the final i must be 100000.
public class ThreadJoinDemo{
	public volatile static int i = 0;
	static class T1  extends Thread {
		@Override
		public void run() {
			for(i=0;i<100000;i++);
		}
	}
	public static void main(String[] args) throws InterruptedException {
		T1 t1 = new T1();
		t1.start();
		t1.join();
		System.out.println(i);
	}

}
 Thread resource yield - yield: Thread.yield() is a static native method. The meaning of giving up is very clear, giving up CPU resources. However, give up what I still have to fight for! 4. Classification and management of threads 1. Grouping of threads - Thread groups divide threads into groups, and give them a nice name to facilitate management. By default, the thread group where the newly created thread is located is the parent group of the created thread.
public class ThreadGroupDemo implements Runnable{

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ThreadGroup tg = new ThreadGroup("zhaodf");
		Thread t1 = new Thread(tg, new ThreadGroupDemo(), "T1");
		Thread t2 = new Thread(tg, new ThreadGroupDemo(), "T2");
		Thread t3 = new Thread(new ThreadGroupDemo());
		t1.start();
		t2.start();
		t3.start();
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getThreadGroup().getName()+"_"+Thread.currentThread().getName());
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace ();
		}
	}

}
  2. Daemon thread: Who is guarded by the daemon thread? It is the user thread that is guarded. If the user thread does not exist, it is meaningless, so it stops.
public class Daemon {
	public static class DaemonT extends Thread{
		@Override
		public void run() {
			while(true){
				System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"_i am alive");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace ();
				}
			}
		}
	}
	
	/**
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		Thread t = new DaemonT();
		//The daemon thread must be set before the start method, so that t becomes the daemon thread, and the main thread main becomes the user thread. When the main thread sleeps for 2 seconds, the daemon thread also exits
		//If placed after start, Exception in thread "main" java.lang.IllegalThreadStateException will be thrown
		t.setDaemon(true);
		t.start();
		System.out.println(System.currentTimeMillis()+"_"+"主线程名称:"+Thread.currentThread().getName());
		Thread.sleep(2000);
	}

}
   3. The priority of the thread: The priority of the thread does not guarantee that the thread executes first, so pay attention to this.
public class PriorityDemo{

	public static class HightPriority extends Thread{
		static int count = 0;
		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(true){
				synchronized (PriorityDemo.class) {
					count++;
					if(count>10000){
						System.out.println("HightPriority is complete");
						break;
					}
				}
			}
		}

	}
	
	public static class LowerPriority extends Thread{
		static int count = 0;
		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(true){
				synchronized (PriorityDemo.class) {
					count++;
					if(count>10000){
						System.out.println("LowerPriority is complete");
						break;
					}
				}
			}
		}
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread high = new HightPriority();
		Thread low = new LowerPriority();
		// Setting the priority does not guarantee that the thread will execute first
		high.setPriority(Thread.MAX_PRIORITY);
		low.setPriority(Thread.MIN_PRIORITY);
		high.start();
		low.start();
	}

}
 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326170704&siteId=291194637