Introduction of 0.

This series begins with the introduction to Java multithreading. This section covers the basics of multithreading.

1. Processes and threads

1.1 What is a process?

Process is the program in the running process, just like wechat and QQ in the mobile phone running, these are called process.

1.2 What is a thread?

A thread is the execution unit of a process, just like a music software can listen to music, download music, these tasks are done by threads.

1.3 Relationship between processes and threads

  • A process can have multiple threads, and a thread must have a parent process
  • Threads share the shared resources of the parent process and cooperate with each other to complete the tasks required by the process
  • One thread can create and destroy another thread, and multiple threads of the same process can execute concurrently

2. How do I create a thread

There are three ways to create threads in Java, described in detail below.

2.1 Inherits the Thread class to create threads

The steps to create a Thread using the inherited Thread class are as follows:

  1. Create a new class that inherits Thread and overwrites its run() method.
  2. Create an instance of the Thread subclass.
  3. Call the start() method of the subclass instance to start the thread.

Code examples are as follows:

public class ThreadDemo extends Thread { // 1. Create a new class that inherits Thread and overwrites its run() method. @Override public voidrun() {
		System.out.println("Hello Thread"); } public static void main(String[] args) { // 2. Create an instance of the Thread subclass. ThreadDemo threadDemo = new ThreadDemo(); // 3. Call the start() method of the subclass instance to start the thread. threadDemo.start(); }}Copy the code

The print result is as follows:

Hello Thread
Copy the code

2.2 Implementing the Runnable interface to create threads

The steps to create a thread using the implementation Runnable interface are:

  1. Create a class that implements the Runnable interface and override its run() method.
  2. Create an instance of the implementation class.
  3. Pass this instance into the Thread(Runnable R) constructor to create a Thread instance.
  4. Call the start() method of the Thread object.

Code examples are as follows:

public class RunnableDemo implements Runnable { // 1. Create a class that implements the Runnable interface and override its run() method. @Override public voidrun() {
		System.out.println("Hello Runnable"); } public static void main(String[] args) { // 2. Create an instance of the implementation class. RunnableDemo runnableDemo = new RunnableDemo(); // 3. Pass this instance into the Thread(Runnable r) constructor to create a Thread instance. Thread thread = new Thread(runnableDemo); // 4. Call the start() method of the Thread object. thread.start(); }}Copy the code

The print result is as follows:

Hello Runnable
Copy the code

2.3 Create threads using Callable and FutureTask

A thread created using this method gets a return value. The steps to create a thread using the implementation Callable and FutureTask are:

  1. Create a class that implements the Callable interface and rewrite the Call () method.
  2. Create an instance of the Callable interface implementation class.
  3. Create a FutureTask instance by passing the implementation class instance of Callable into the FutureTask(Callable Callable) constructor.
  4. Create the Thread instance by passing the FutureTask instance into the Thread(Runnable R) constructor.
  5. Call the start() method of the Thread object.
  6. Call the Get () method of the FutureTask instance object to get the return value.

Code examples are as follows:

public class CallableDemo implements Callable<String> { // 1. Create a class that implements the Callable interface and rewrite the Call () method. @Override public String call() throws Exception { System.out.println("CallableDemo is Running");
		return "Hello Callable"; } public static void main(String[] args) { // 2. Create an instance of the Callable interface implementation class. CallableDemo callableDemo = new CallableDemo(); // 3. Pass the implementation class instance of Callable into the FutureTask(Callable<V> Callable) constructor to create an instance of FutureTask. FutureTask<String> futureTask = new FutureTask<>(callableDemo); // 4. Pass the FutureTask instance into the Thread(Runnable r) constructor to create the Thread instance. Thread thread = new Thread(futureTask); // 5. Call the start() method of the Thread object. thread.start(); // 6. Call the Get () method of the FutureTask instance object to get the return value. try { System.out.println(futureTask.get()); } catch (Exception e) { e.printStackTrace(); }}}Copy the code

The print result is as follows:

CallableDemo is Running
Hello Callable
Copy the code

3. Thread lifecycle

Once a thread is started, it follows a life cycle through five states: new, ready, running, blocked and dead. Understanding the life cycle of a thread will help you understand the following thread knowledge.

3.1 New Status

This state means that a thread has just been created without any of the dynamic characteristics of a thread.

3.2 Ready State

When the thread object calls the start() method, the thread is in a ready state. A thread in this state does not start running, but is ready to run.

3.3 Operating Status

Once the ready thread has acquired the CPU, it executes the run() method, and the thread is running.

3.4 Blocking Status

When a thread is paused, it is blocked.

3.5 Death Status

When a thread is stopped, the thread is dead.

In fact, the most important thing to master multithreading is to be familiar with the state of the control thread, so that each thread can better serve us, the following to explain the method of control thread.

4. Control threads

4.1 the sleep ()

4.1.1 Thread lifecycle changes

4.1.2 Method preview

public static native void sleep(long millis)
public static void sleep(long millis, int nanos)
Copy the code

This method means that the running thread is blocked for as long as the thread is blocked. Millis is millisecond, nanos is nanosecond.

4.1.3 Code Examples

public class SleepDemo {
	
	public static void main(String[] args) throws Exception {
		
		for(int i = 0; i < 10; i++) {
			System.out.println("Hello Thread Sleep"); Thread.sleep(1000); }}}Copy the code

After the above code runs, it prints Hello Thread Sleep every second.

4.2 Thread Priority

4.2.1 Method preview

public final void setPriority(int newPriority)
public final int getPriority()
Copy the code

As you can see from the method name, the above two methods set and get priority, respectively. Note that the priority ranges from 1 to 10 and can also be set using the following three static variables:

  • MAX_PRIORITY: the priority is 10
  • NORM_PRIORITY: The priority is 5
  • MIN_PRIORITY: the priority is 1

4.3 yield ()

4.3.1 Changes in the thread lifecycle

4.3.2 Method preview

public static native void yield();
Copy the code

This method means that the running thread is returned to the ready state without blocking the thread. It is possible that the thread scheduler will continue to call the thread after it has called yield(). The important thing to note about this method is that it only gives in to threads with a higher or equal priority that are in the ready state.

4.3.3 Code Examples

public class YieldDemo extends Thread {

	@Override
	public void run() {

		for (int i = 0; i < 50; i++) {
			System.out.println(getName() + "" + i);

			if(i == 20) { Thread.yield(); } } } public static void main(String[] args) { YieldDemo yieldDemo1 = new YieldDemo(); YieldDemo yieldDemo2 = new YieldDemo(); yieldDemo1.start(); yieldDemo2.start(); }}Copy the code

Code output:

Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-1 5
Thread-1 6
Thread-1 7
Thread-1 8
Thread-1 9
Thread-1 10
Thread-1 11
Thread-1 12
Thread-1 13
Thread-1 14
Thread-0 0
Thread-0 1
Thread-0 2
Thread-1 15
Thread-0 3
Thread-1 16
Thread-1 17
Thread-1 18
Thread-1 19
Thread-1 20
Thread-0 4
Thread-0 5
Thread-0 6
Thread-0 7
Thread-1 21
Thread-0 8
Thread-1 22
Thread-0 9
Thread-1 23
Thread-0 10
Thread-0 11
Thread-0 12
Thread-1 24
Thread-1 25
Thread-0 13
Thread-1 26
Thread-1 27
Thread-0 14
Thread-0 15
Thread-1 28
Thread-0 16
Thread-0 17
Thread-0 18
Thread-1 29
Thread-0 19
Thread-0 20
Thread-1 30
Thread-1 31
Thread-0 21
Thread-1 32
Thread-1 33
Thread-1 34
Thread-1 35
Thread-1 36
Thread-1 37
Thread-1 38
Thread-1 39
Thread-1 40
Thread-1 41
Thread-1 42
Thread-1 43
Thread-1 44
Thread-1 45
Thread-1 46
Thread-1 47
Thread-1 48
Thread-1 49
Thread-0 22
Thread-0 23
Thread-0 24
Thread-0 25
Thread-0 26
Thread-0 27
Thread-0 28
Thread-0 29
Thread-0 30
Thread-0 31
Thread-0 32
Thread-0 33
Thread-0 34
Thread-0 35
Thread-0 36
Thread-0 37
Thread-0 38
Thread-0 39
Thread-0 40
Thread-0 41
Thread-0 42
Thread-0 43
Thread-0 44
Thread-0 45
Thread-0 46
Thread-0 47
Thread-0 48
Thread-0 49
Copy the code

When thread-1 20 is printed, thread-0 4 is executed next. When thread-20 is printed, the next execution is Thread-1 30. It is important to note, however, that not every print is the same, because the thread scheduler may continue to start the thread after it calls yield().

4.4 the join ()

4.4.1 Changes in the thread lifecycle

4.4.2 Method Preview

public final void join() throws InterruptedException
public final synchronized void join(long millis) throws InterruptedException
Copy the code

This method actually has two threads, that is, one thread has another thread calling the join() method in its execution body. For example, if Thread2 calls join() in the body of Thread1’s run() method, Thread1 will block and wait until Thread2 completes or join() time expires.

4.4.3 Join () code examples


public class JoinDemo extends Thread {
	
	@Override
	public void run() {
		for(int i = 0; i < 50; i++) {
			
			System.out.println(getName() + "" + i);
		}
	}
	
	public static void main(String[] args) throws Exception {
		
		JoinDemo joinDemo = new JoinDemo();
		
		for(int i = 0; i < 50; i++) {
			
			if(i == 20) {
				
				joinDemo.start();
				joinDemo.join();
				
			}
			
			System.out.println(Thread.currentThread().getName() + ""+ i); }}}Copy the code

Code output:

main 0 main 1 main 2 main 3 main 4 main 5 main 6 main 7 main 8 main 9 main 10 main 11 main 12 main 13 main 14 main 15 main 16 main 17 main 18 main 19 main 20 Thread-0 0 Thread-0 1 Thread-0 2 Thread-0 3 Thread-0 4 Thread-0 5 Thread-0 6 Thread-0 7 Thread-0 8 Thread-0 9 Thread-0 10 Thread-0 11 Thread-0 12 Thread-0 13 Thread-0 14 Thread-0 15 Thread-0 16 Thread-0 17 Thread-0 18 Thread-0 19 Thread-0 20 Thread-0 21 Thread-0 22 Thread-0 23 Thread-0 24 Thread-0 25 Thread-0 26 Thread-0 27 Thread-0 28 Thread-0 29 Thread-0 30 Thread-0 31 Thread-0 32 Thread-0 33 Thread-0 34 Thread-0 35 Thread-0 36 Thread-0 37 Thread-0 38 Thread-0 39 Thread-0 40 Thread-0 41 Thread-0 42 Thread-0 43 Thread-0 44 Thread-0 45 Thread-0 46 Thread-0 47 Thread-0 48 Thread-0 49 main 21 main 22 main 23 main 24 main 25 main 26 main 27 main 28 main 29 main 30 main  31 main 32 main 33 main 34 main 35 main 36 main 37 main 38 main 39 main 40 main 41 main 42 main 43 main 44 main 45 main  46 main 47 main 48 main 49Copy the code

The code above is actually two threads, one is thread0, and the other is main. As can be seen from the printed result, when the main Thread reaches main 20, thread-0 0 is executed, and main does not continue to execute until thread-0 is finished.

4.4.4 Join (Long Millis) code examples

public class JoinDemo extends Thread {
	
	@Override
	public void run() {
		for(int i = 0; i < 50; i++) {
			
			System.out.println(getName() + "" + i);
		}
	}
	
	public static void main(String[] args) throws Exception {
		
		JoinDemo joinDemo = new JoinDemo();
		
		for(int i = 0; i < 50; i++) {
			
			System.out.println(Thread.currentThread().getName() + "" + i);
			
			if(i == 20) { joinDemo.start(); joinDemo.join(1); }}}}Copy the code

Print result:

main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
main 10
main 11
main 12
main 13
main 14
main 15
main 16
main 17
main 18
main 19
main 20
Thread-0 0
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-0 6
Thread-0 7
Thread-0 8
Thread-0 9
Thread-0 10
Thread-0 11
Thread-0 12
Thread-0 13
Thread-0 14
Thread-0 15
Thread-0 16
Thread-0 17
Thread-0 18
Thread-0 19
Thread-0 20
Thread-0 21
Thread-0 22
Thread-0 23
Thread-0 24
Thread-0 25
Thread-0 26
Thread-0 27
Thread-0 28
Thread-0 29
Thread-0 30
Thread-0 31
Thread-0 32
Thread-0 33
main 21
main 22
Thread-0 34
main 23
Thread-0 35
Thread-0 36
main 24
main 25
main 26
Thread-0 37
main 27
Thread-0 38
main 28
Thread-0 39
main 29
Thread-0 40
main 30
Thread-0 41
main 31
Thread-0 42
main 32
main 33
main 34
main 35
Thread-0 43
Thread-0 44
Thread-0 45
main 36
Thread-0 46
main 37
main 38
main 39
main 40
main 41
main 42
main 43
main 44
main 45
main 46
main 47
main 48
main 49
Thread-0 47
Thread-0 48
Thread-0 49
Copy the code

This code is basically the same as the code in Section 4.4.3, except that join() is changed to join(1). You can see that main does not wait for thread0 to finish executing.

4.5 Background Threads

4.5.1 Method Preview

public final void setDaemon(boolean on)
public final boolean isDaemon()
Copy the code

This method is to set the thread as background thread, the characteristics of background thread is finished when the current thread has finished. When this method is set to true, the thread is set to background. IsDaemon () returns whether the thread is a background thread.

4.5.2 Code Examples


public class DaemonDemo extends Thread {

	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			System.out.println(getName() + ""+ isDaemon() + "" + i);
		}
	}
	
	public static void main(String[] args) {
		
		DaemonDemo daemonDemo = new DaemonDemo();
		
		daemonDemo.setDaemon(true);
		
		daemonDemo.start();
		
		for(int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + ""+ i); }}}Copy the code

Print result:

main 0
main 1
main 2
main 3
main 4
Thread-0 true 0
main 5
main 6
main 7
main 8
main 9
Thread-0 true 1
Thread-0 true 2
Thread-0 true 3
Thread-0 true 4
Thread-0 true 5
Thread-0 true 6
Thread-0 true 7
Thread-0 true 8
Thread-0 true 9
Thread-0 true 10
Thread-0 true 11
Copy the code

From the printed result, it can be seen that after main is executed, thread-0 ends without completion of execution.

5. Some caveats

5.1 The difference between sleep() and yield()

Role in sleep() yield()
Give other threads a chance to execute Will give other threads the chance to execute, regardless of the priority of other threads Only threads with the same or higher priority are given a chance to execute
Affects the state of the current thread From blocked to ready Go straight to the ready state
abnormal InterruptedException needs to be thrown No exceptions need to be thrown

Multithreading series:

Multithreading in detail (2) — a few concepts you have to know