Thread state switching

Thread state switching

The thread has gone through 5 states from creation and start to death: new, ready, running, blocked and dead

Insert picture description here
5 state transitions of thread changes:

1. New state (New): A thread object is newly created. new Thread()

2. Ready state (Runnable): After the thread object is created, other threads call the start() method of the object. The start method can only be called for the thread object in the newly created state, otherwise IllegalThreadStateException

The thread in this state is located in the executable thread pool, becomes executable, and waits for the right to use the CPU.

3. Running state: The thread in the ready state has acquired the CPU. Execute the program code. Note that there will be multiple threads executing in parallel on a multi-processor machine

Nowadays, most desktop and server operating systems adopt a preemptive scheduling strategy of time slice rotation method, and the system will consider the priority of the thread when selecting the next execution thread

Calling the yield method can make the running thread ready

4. Blocked state (Blocked): Blocked state is the thread giving up the right to use the CPU for some reason. Temporarily stop execution. Until the thread enters the ready state, it has the opportunity to go to the execution state. Thread switching is controlled by the underlying platform and has a certain degree of randomness

There are three types of jams:

(1) Waiting for blockage: The executing thread executes the wait() method, and the JVM will put the thread into the waiting pool.

(2) Synchronization blockage: When the thread of execution acquires the synchronization lock of the object, if the synchronization lock is occupied by another thread. The JVM will put the thread into the lock pool.

(3) Other blockages: when the executing thread executes the sleep() or join() method, or when an I/O request is issued. The JVM will put the thread into a blocked state. When the sleep() state times out, join() waits for the thread to terminate or time out, or when the I/O processing is complete. The thread goes into the ready state again.

5. Dead state (Dead): The thread finishes running or exits the run() method due to an exception, and the thread ends its life cycle.

You can also end the thread by directly calling the stop method of the thread, but this method is easy to cause data inconsistency, and it is generally not recommended to use

When the main thread ends, other threads will not be affected in any way and will not end. Once the child thread is started, it will have the same status as the main thread and will not be affected by the main thread.

Note: Do not try to restart a dead thread by calling the start method, the thread will not be executed as a thread again, otherwise it will be abnormal

common problem

  • How to force start a thread
    There is no way to force start a thread in Java, it is controlled by the thread scheduler and Java does not publish related APIs.
  • Garbage collection
    System.gc() or Runtime.getRuntime().gc() can notify garbage collection, but garbage collection is a low-priority thread, and the specific running time is unpredictable
  • Methods that are no longer recommended
    Do not use the stop method to stop a thread. Because the stop method is too extreme, synchronization problems will occur and the data will be inconsistent. So you can consider setting a flag, through return, break, exception and other means to control the flow to stop naturally
Thread t1=new Thread(() -> {
    
     
		for(int i=0;i<100;i++) 
			System.out.println(Thread.currentThread()+"--"+i); 
		}); 
	t1.start(); 
	TimeUnit.MICROSECONDS.sleep(10); 
	t1.stop(); 
	
	//可以通过其它方式实现线程的停止 
	class MyThread extends Thread {
    
     
		private boolean flag = true; 
		@Override 
		public void run() {
    
     
			for (int i = 0; i < 100 && flag; i++) 
				System.out.println(Thread.currentThread() + "--" + i); 
		}
		public void setFlag(boolean flag) {
    
     
			this.flag = flag; 
		} 
	}

The suspend() method is used to suspend the execution of a thread. This method is easy to cause deadlock, because the thread still occupies the resource when it is suspended, which will cause other threads that need the resource to wait in a loop with the thread, resulting in death The lock resume() method is used to resume the execution of the thread. suspend() and resume() methods: the two methods are used together. suspend() makes the thread enter the blocked state and will not automatically resume. The corresponding resume() must be called to make the thread re-enter the executable state

The sleep method makes the current thread sleep

Defined in the Thread class

public static native void sleep(long millis)throws InterruptedException

Let the current thread sleep for a specified time. The accuracy of the sleep time depends on the system clock and CPU scheduling mechanism. If necessary, you can wake up the sleeping thread by calling the interrupt() method

public void interrupt(){
    
    
	if(this!=Thread.currentThread())
		checkAccess();
	synchronized(blockerLock){
    
    
		Interruptible b=blocker;
		if(b!=null){
    
    
			interrupt0();
			b.interrupt(this);
			return;
		}
	}
	interrupt0();
}

The acquired lock resources are not released. If the sleep method is called in the synchronization context, other threads cannot enter the current synchronization block or synchronization method.

Exercise: implement a time display: update every second (for example, countdown)

自定义格式的时间显示 DateFormat---SimpleDateFormat 
DateFormat df=new SimpleDateFormat("yyyy-MM-ddE hh:mm:ss"); 
for (;;) {
    
     //相当于while(true){} 
	Date now = new Date(); 
	System.out.println(df.format(now)); 
	try {
    
    
		Thread.sleep(1000); 
	} catch (InterruptedException e) {
    
    
		e.printStackTrace(); 
	} 
}

When the thread enters the dormant state, it will periodically end the dormancy. If you need to wake up in advance, you need to implement the interrupt method. The so-called interrupt method actually generates an exception InterruptedException

public static void main(String[] args) throws Exception {
    
    
	DateFormat df = new SimpleDateFormat("yyyy-MM-ddE hh:mm:ss");
	Thread t1 = new Thread(() -> {
    
    
		while (true) {
    
    
			Date now = new Date();
			System.out.println(df.format(now));
			try {
    
     // TimeUnit.SECONDS.sleep(10);
				Thread.sleep(10000);// 子线程进入休眠阻塞状态,当超时后自动进入就绪状态,等待下次 调度执行
			} catch (InterruptedException e) {
    
    
				e.printStackTrace();
			}
		}
	});
	t1.start();
	Thread.sleep(200);
	t1.interrupt(); // 唤醒处于休眠状态的线程,在子线程中会导致InterruptedException
	System.out.println("main.....");
}

wait (defined in Object)

  • The function of wait() is to let the current thread enter the waiting state. At the same time, wait() will also let the current thread release the lock it holds. Until other threads call the notify() method or notifyAll() method of this object, the current thread is awakened and enters the ready state
  • The function of notify() and notifyAll() is to wake up the waiting threads on the current object; notify() is to wake up a single thread, and notifyAll() is to wake up all threads.
  • wait(long timeout) makes the current thread in a "waiting (blocking) state", "until other threads call the notify() method or notifyAll() method of this object, or the specified amount of time is exceeded", the current thread is awakened (enter " Ready state").

Let the current thread enter the waiting state, when other threads call the notify() or notifyAll() method, the current thread enters the ready state

The wait method must be called in a synchronization context, for example: a synchronized method block or a synchronized method, which means that if you want to call the wait method, the premise is that the lock resource on the object must be acquired

When the wait method is called, the current thread will release the acquired object lock resource and enter the waiting queue, and other threads can try to acquire the lock resource on the object

// 创建锁对象,保证唯一性
Object obj = new Object();
new Thread() {
    
    
	public void run() {
    
    
		// 保证等待和唤醒只能执行一个,需要使用同步技术
		synchronized (obj) {
    
    
			System.out.println("点外卖");
			// 调用wait方法,放弃CPU的执行权,进入WAITING状态(无限等待)
			obj.wait(1000);
			// 唤醒之后的代码
			System.out.println("外卖已到达");
		}
	}
}.start();

sleep vs wait

wait sleep
Synchronize The wait method can only be called in the synchronization context, otherwise an IllegalMonitorStateException will be thrown No need to call in synchronized method or synchronized block
Role object The wait method is defined in the Object class and acts on the object itself The sleep method is defined in Thread and acts on the current thread
Release lock resources Yes no
Wake-up condition Other threads call the object's notify() or notifyAll() method Timeout or call interrupt() method body
Method attributes wait is an instance method sleep is a static method

Both wait and sleep in Java programs cause some form of pause, and they can meet different needs. The wait() method is used for inter-thread communication. If the wait condition is true and other threads are awakened, it will release the lock. The sleep() method only releases CPU resources or stops the current thread from executing for a period of time, but does not release the lock.

join method

The main function is synchronization, which can make parallel execution between threads become serial execution. When the join() method of thread B is called in thread A, it means that thread A can continue execution only when thread B finishes executing. The thread calling this method will be blocked

  • The function of the method join(long) is implemented internally using the wait(long) method, so the join(long) method has the characteristic of releasing the lock. But sleep(long) does not release the lock.

Exercise: write 10 threads, the first thread is added from 1 to 10, the second thread is added from 11 to 20... the tenth thread is added from 91 to 100, and finally the results of the ten threads are added

Use the Callable interface, because future.get() can block the execution of the current thread

FutureTask[] fs = new FutureTask[10];
for (int i = 0; i < 10; i++) {
    
    
	fs[i] = new FutureTask<>(new MyCallable(i * 10 + 1, (i + 1) * 10));
	new Thread(fs[i]).start();
}
int res = 0;
for (FutureTask ft : fs)
	res += (Integer) ft.get();
System.out.println(res);

Using the Runnable interface, the result of 10 child threads must be accumulated in the main thread after the execution of the child thread is finished through join

MyRunnable[] arr = new MyRunnable[10];
		Thread[] ts = new Thread[10];
		for (int i = 0; i < 10; i++) {
    
    
			MyRunnable mr = new MyRunnable(i * 10 + 1, (i + 1) * 10);
			arr[i] = mr;
			ts[i] = new Thread(mr);
			ts[i].start();
		}
		int res = 0;
		for (int i = 0; i < 10; i++) {
    
    
			ts[i].join();
			res += arr[i].getRes();
		}
		System.out.println("计算结果为:" + res);

Guess you like

Origin blog.csdn.net/qq_43480434/article/details/114040760