preface

Welcome to our GitHub repository Star: github.com/bin39232820… The best time to plant a tree was ten years ago, followed by now

omg

Today we are going to talk about the basics of concurrent programming, the basics of multithreading. Without multithreading, there would be no concurrency, right? Here are the links to previous chapters:

  • 🔥 the most comprehensive series of Concurrent Java programming challenges ever
  • 🔥 is the most comprehensive Java concurrency series on the underlying implementation of Java concurrency
  • 🔥 The most complete series of Concurrent Java memory models ever

Introduction to Threads

  • What is a thread

    A thread is the smallest unit in which an operating system can schedule operations. It is contained within the process and is the actual operating unit within the process. A thread is a single sequential flow of control in a process, and multiple threads can be concurrent in a process, each performing a different task in parallel.

  • Why multithreading

    There are more and more processor cores, faster response times and better programming models with multithreading.

  • Thread priority

    Modern operating systems basically schedule running threads in the form of time. Each time slice allocated by the operating system will be allocated according to the priority of the thread. The higher the priority, the first to obtain execution resources.

In Java threads, the priority is controlled by an integer member variable priority, which ranges from 1 to 10. The setPriority(int) method can be used to change the priority during thread construction. The default priority is 5.

Thread state

  • NEW Initial state
  • RUNNABLE Running status
  • BLOCKED state
  • WAITING state
  • TIME_WAITING Indicates the timeout waiting status
  • TERMINATED state

Thead class source code interpretation

Java all multithreading implementation, are achieved through the encapsulation of Thread class, so in-depth Thread class, for in-depth understanding of Java multithreading is necessary

Inheritance relationships

The main properties

/* * Thread name, specified by construct parameter */ private volatile String name; /* * Indicates the priority of the thread. The higher the priority is, the higher the priority is. (The maximum value is 10, the minimum value is 1, and the default value is 5.) */ private int priority; Private Boolean daemon = false; private Boolean daemon = false; /* * Private Runnable target; /* * Thread group represents a collection of threads. In addition, thread groups can also contain other thread groups. Thread groups form a tree in which each thread group has a parent thread group in addition to the initial thread group. */ private ThreadGroup group; /* * Thread ID */ private long tid; */ private static long threadSeqNumber; Private static int threadInitNumber /* * The number of threads that are assigned to thread.name */ private static int threadInitNumber /* * The number of states that a thread must pass through from creation to final death. * In general, threads include the following states: Create (new), run (runnable), blocked (time waiting), dead (dead) */ private volatile int threadStatus = 0;Copy the code

The constructor

// Pass in the Runnable interface implementation Thread(Runnable target). ThreadGroup (Runnable target) ThreadGroup (Runnable target) ThreadGroup (Runnable target) Thread(ThreadGroup group, Runnable target, String name) Thread(ThreadGroup group, Runnable Target, String name, long stackSize)Copy the code

There are a couple of ways to create a thread, but basically there are 4 ways to create a thread, so I’m not going to write this code, because it’s going to be too long

  • The first option is to continue the Thread class and override the run method, which overrides Runnable,
  • The second is to implement Runnable, same thing
  • The third way is to create a thread through FutureTask. How does this work? But again, the parent of this class inherits Runnable, and the special thing about this is that when the thread is done, it can return a value.
  • The fourth is to create a thread from a thread pool (used in production environments).

Thread default name Production rule:

// Current default thread name: "Thread-" + nextThreadNum() public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } -- private static int threadInitNumber; private static int threadInitNumber; private static synchronized int nextThreadNum() { return threadInitNumber++; }Copy the code

Thread privatized implementation, talk about this initialization method

/** * Initializes a Thread. * * @param g the Thread group * @param target the object whose run() method gets called * @param name the name of the new Thread * @param stackSize the desired stack size for the new thread, or * zero to indicate that this parameter is to be ignored. * @param acc the AccessControlContext to inherit, or * AccessController.getContext() if null */ private void init(ThreadGroup g, Runnable target, String name, Long stackSize, AccessControlContext ACC) {// Thread must set the name, If (name == null) {throw new NullPointerException("name cannot be null"); } this.name = name.toCharArray(); // Parent Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); If (g == null) {/* Determine if it's an applet or not */ / Determine if it's an applet or not * If there is a security manager, ask the security manager what to do. */ If (security! = null) { g = security.getThreadGroup(); } // If the security manager also does not know about the thread group, then get the thread group from the parent thread, /* If the security doesn't have a strong opinion of the matter use the parent thread group. */ If (g == null) { g = parent.getThreadGroup(); } } /* checkAccess regardless of whether or not threadgroup is explicitly passed in. */ g.checkAccess(); /* * Do we have the required permissions? GetContextClassLoader and setContextClassLoader */ if (security! = null) { if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } // add unstarted thread to thread group g.adddunstarted (); this.group = g; /* Sets whether the current thread is a daemon thread. The default is the same as the ThreadGroup setting of the current class. In the case of daemons, the end of the current thread exits as the main thread exits. * The JVM exits when there are no active non-daemons on the system. */ this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); if (security == null || isCCLOverridden(parent.getClass())) this.contextClassLoader = parent.getContextClassLoader(); else this.contextClassLoader = parent.contextClassLoader; this.inheritedAccessControlContext = acc ! = null ? acc : AccessController.getContext(); this.target = target; setPriority(priority); if (parent.inheritableThreadLocals ! = null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* set the specified stackSize. If the size is not specified, it is declared in the JVM initialization parameter: Xss parameter is specified */ this.stacksize = stackSize; /* Set thread ID */ tid = nextThreadID(); }Copy the code

The start method

A thread cannot execute the start method once it has been started. The status of the thread started is no longer 0

/* Causes this thread to start executing; The Java Virtual Machine calls the run method of this thread. The result is two threads running at the same time: the current thread (which returns to the start method from the call) and another thread (which executes its run method). It is never legal to start a thread more than once. In particular, once execution is complete, the thread may not be able to restart. @ exception IllegalThreadStateException if the thread has been started. @see #run () @see #stop () */ public synchronized void start() {/** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future Buta pile cannot be called any more than A pile of bricks. Buta pile cannot be called any more than A pile of bricks. * * A zero status value pile to state "NEW". Cannot be started again if (threadStatus! = 0) throw new IllegalThreadStateException(); /* Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * And the group's unstarted count can be decreed. */ /* Notify a group that the thread is about to be started * so that it can be added to the group's list of threads * and that the group's unstarted count can be decremented. */ group.add(this); boolean started = false; try { start0(); started = true; } finally {try {// If the thread fails to start, remove it from the thread group if (! started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */ } }}Copy the code

In fact, the source code is also simple, is to start the thread and then let the group of threads to be started minus 1, if the failure, he added to the failed array.

Join () method

Make the parent thread wait for the child thread to finish before continuing.

/** * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. * * <p> This implementation uses a loop of {@code this.wait} calls * conditioned on {@code this.isAlive}. As a thread terminates the * {@code this.notifyAll} method is invoked. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances. * * @param millis * the time to wait in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) {// If (millis == 0) {while (isAlive()) {wait(0); While (isAlive()) {long delay = millis-now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; }}}Copy the code

First of all, what about the Join method? There are several overloaded methods. If you pass no arguments, your timeout will never expire. As long as the thread calling the JOIN method does not complete, the current thread will wait

Note:

  • The Join method is implemented using the wait method, so the object lock is released.

  • The caller thread is in WAITING state.

  • Join needs to be called after start

Interrupt method

Thread interrupts had the stop method in previous versions, but it was made obsolete. There is no way to force a thread to terminate!

Because the stop method can cause one thread A to terminate another thread B

  • Terminated thread B immediately releases the lock, which may leave the object in an inconsistent state.
  • Thread A does not know when thread B can be terminated. If thread B is still running the computation phase, thread A calls stop to terminate thread B

In short, the Stop method is so violent and unsafe that it is outdated.

We typically use interrupts to request the termination of threads ~

  • Note that an interrupt does not actually stop a thread, it merely signals the thread that it should be terminated (this is important to understand!).
  • In other words, the Java designer actually wants the thread to terminate itself, and from the above signals, it can decide what business to process.
  • It is up to the notified thread to decide whether to interrupt or continue
Thread t1 = new Thread(new Runnable(){public void run(){// While (! Thread. The currentThread. The isInterrupted ()) {/ / normal task code... } // Interrupt handler code...... doSomething(); } } ).start();Copy the code

Again: Calling interrupt() doesn’t actually kill the current thread, it just sets an interrupt flag. This break flag gives us a sense of when to do something! It’s up to us to decide when to interrupt, so we can safely terminate the thread!

// Unless you interrupt yourself, CheckAccess will be called /** * Interrupts this thread. ** <p> Unless the current thread is interrupting itself, which is * always permitted, the {@link #checkAccess() checkAccess} method * of this thread is invoked, {@link * SecurityException} to be thrown. * / When a thread blocks wat, join, or sleep, // The interrupt status of the thread is cleared to false, and the interrupted thread will receive an interrupt exception. * <p> If this thread is blocked in an invocation of the {@link * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link * Object#wait(long, int) wait(long, int)} methods of the {@link Object} * class, or of the {@link #join()}, {@link #join(long)}, {@link * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)}, * methods of this class, Then its interrupt status will be cleared and it * will receive an {@link InterruptedException}. Channel will be closed, and the thread of the interrupted status will be set to true, / / and interrupt threads will receive a ClosedByInterruptException anomalies. * <p> If this thread is blocked in an I/O operation upon an {@link * java.nio.channels.InterruptibleChannel InterruptibleChannel} * then the channel will be closed, the thread's interrupt * status will be set, And the thread will receive a {. @ the link * Java nio. Channels. ClosedByInterruptException}. * / / if the thread block in the selector method, The interrupt thread's interrupt status will be set to true and return immediately from the SELECT operation, and // only the selector wakeup method called may return a non-zero value. * <p> If this thread is blocked in a {@link java.nio.channels.Selector} * then the thread's interrupt status will be set  and it will return * immediately from the selection operation, possibly with a non-zero * value, Just as if the selector 's {. @ the link * Java nio. Channels. Selector# wakeup wakeup} method were invoked. * / / if not above said several times, The interrupt status of the thread will be set. * <p> If none of the previous conditions hold then this thread's interrupt * status will be set. </p> * * <p> Interrupting a thread that is not alive need not have any effect. * * @throws SecurityException * if the current thread Cannot modify this thread * * @revised 6.0 * @spec jSR-51 */ public void interrupt() {if (this! = Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b ! = null) { interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } interrupt0(); }Copy the code

There are two other methods (to check if the thread is interrupted) :

  • The static method interrupted()–> clears the interrupt flag
  • The example method isInterrupted()–> does not clear the interrupt flag bit

Sleep method (Long Millis)

public static native void sleep(long millis) throws InterruptedException;

Copy the code

Note:

  • When a thread is called, the CPU is occupied and does not work. In this case, some CPU resources of the system are occupied and other threads cannot enter the system.

  • The sleep method does not release the lock.

The yield () method

public static native void yield();
Copy the code

Note:

  • Invoking the yield method causes the current thread to surrender CPU privileges, giving threads with the same priority an opportunity to obtain CPU execution time
  • Instead of making a thread BLOCKED, calling yield returns the thread to a RUNNABLE state, but does not guarantee a quick transition. (I can compete again myself)
  • Lock not released

At the end

The first section of chapter 4 is finished, talking about Thread, which is not very deep. It is ok to learn with it. Ok, that’s all for today

I have a goal to write two or three articles a week. I hope I can keep it up for a year. I hope you can give me more suggestions so that I can learn more and make progress together.

Daily for praise

Ok, everybody, that’s all for this article, you can see people here, they are real fans.

Creation is not easy, your support and recognition, is the biggest motivation for my creation, we will see in the next article

Six pulse excalibur | article “original” if there are any errors in this blog, please give criticisms, be obliged!