This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021.”

Several ways to implement multithreading

  • This is done by inheriting the Thread class
public static void main(String[] args) { new MyThread("A").start(); new MyThread("A").start(); } public class MyThread extends Thread{ private String mThreadName; public MyThread(String threadName){ mThreadName = threadName; } @Override public void run() { super.run(); for (int i = 0; i < 10; I ++) {system.out.println (mThreadName+" run, I ="+ I); try { sleep((long) (Math.random()*10)); } catch (InterruptedException e) { e.printStackTrace(); }}}}Copy the code
  • Implement the Runnable interface
public static void main(String[] args) { new Thread(new MyRunnable("A")).start(); new Thread(new MyRunnable("B")).start(); } public class MyRunnable implements Runnable{ private String mThreadName; public MyRunnable(String threadName){ mThreadName = threadName; } @Override public void run() { for (int i = 0; i < 10; I ++) {system.out.println (mThreadName+" run, I ="+ I); try { sleep((long) (Math.random()*10)); } catch (InterruptedException e) { e.printStackTrace(); }}}}Copy the code
  • Use Callable + FutureTask
CallableTask worker = new CallableTask(); FutureTask<Integer> task = new FutureTask<Integer>(worker); new Thread(task).start(); public class CallableTask implements Callable<Integer> { @Override public Integer call() throws Exception { int hours = 5; int amount = 0; while(hours>0){ System.out.println(" i am working ,rest is "+ hours); amount++; hours--; Thread.sleep(1000); } return amount; }}Copy the code

Implementing the Runnable interface has advantages over inheriting the Thread class:

  • You can avoid the restriction of single inheritance in Java
  • Thread pools can only be placed into classes that implement Runable or Callable, not directly into classes that inherit threads

In Java, at least two threads are started each time a program runs, the main thread and the garbage collection thread. Because every time a class is executed using a Java command, a JVM is actually started, and each JVM is actually starting a process in the operating system

Several states of a thread

  • New state (New) : A New thread object is created

  • Ready state (Runnable) : After a thread object is created, another thread calls the start() method of the object. The thread in this state is in the Runnable thread pool and becomes Runnable. At this time, as long as the CPU has the execution right, it can run and enter the Runnable state.

  • Running: The ready thread can enter this state to execute the code in the run() method once it has been given execution rights from the CPU.

  • Blocked: WHEN a thread loses access to the CPU for some reason, it temporarily stops running and does not return to the running state until it is ready. Blocked is usually classified as follows:

    • Wait blocking: A running thread executes wait(), and the JVM places the thread in the thread wait pool. (Wait () releases the held lock.)
    • Synchronous blocking: When a running thread acquises a synchronized lock on an object, it cannot run if the lock is held by another thread, and the JVM places the thread in the lock pool, blocking it
    • Other blocking: A running thread executes a sleep() or join() method, or makes an I/O request, and the JVM blocks the thread. When the sleep() state times out, the JOIN () wait thread terminates or times out, or the I/O process is complete, the thread returns to the ready state. Sleep () does not release its own lock.
  • Dead: Terminates the life of a thread after it has finished executing or because the program exits the run() method abnormally.

The difference between start() and run() of Thread

Call the start() method

When a thread is created and in its initial state, if the start() method is called, the Java virtual machine calls the thread’s run method, making the thread runnable and waiting for the CPU to allocate the time slice for execution. The thread enters the running state. If the thread is executed, The run () method then runs in the child thread, and when it is finished, the thread enters the terminating state.

Call the run() method

However, if you call the run() method directly, you simply execute the run() method in the thread without putting the thread into an executable state, and the code inside the run method still runs on the main thread.

The difference between sleep (), yield () and wait ()

Sleep () puts the executing thread to sleep (suspends execution) for the specified number of milliseconds

Sleep () causes the current thread to enter a standstill state (blocking the current thread), freeing up CPU usage.

Sleep () is the Static method of Thread; Therefore, he cannot change an object’s machine lock, so when the Sleep() method is called in a Synchronized block, the thread is asleep, but the object’s machine lock is not released, and other threads cannot access the object (holding the object lock even when asleep).

The thread does not necessarily execute immediately after the sleep() sleep period expires, because other threads may be running and not scheduled to abort unless this thread has a higher priority.

The wait() method suspends the thread, releases CONTROL of the CPU, and releases control of the object lock
  • The wait() method is a method in the Object class;
  • When a thread executes a wait() method, it enters the wait pool associated with the object and loses the lock on the object. Other threads can access it;
  • Wait () uses notify or notifyAlll or a specified sleep time to wake up the threads in the current wait pool.
  • Wiat () must be placed in a synchronized block, otherwise you’ll be in the program when the runtime throws the “Java. Lang. IllegalMonitorStateException” exception.
The yield() method suspends the currently executing thread object and executes the other threads

What yield() should do is bring the current running thread back to the runnable state (ready state) to allow other threads with the same priority to get a chance to run. Therefore, the purpose of using yield() is to allow proper rotation of execution between threads of the same priority. In practice, however, there is no guarantee that yield() will yield because the yielding thread may be selected again by the thread scheduler.

Yield () simply yields CPU resources to threads of the same priority, and if there are no threads of the same priority, it will still be executed

The difference between “sleep” and “wait”

  • Wait can only be called in a synchronous environment, but sleep does not.
  • A thread in wait state can be awakened by notify and notifyAll threads, but a thread in sleeping state cannot be awakened by notify.
  • A wait is usually executed conditionally, and a thread stays in wait until a condition is true. But sleep just puts your thread to sleep.
  • The wait method releases the lock of an object when it enters the wait state, but the sleep method does not.
  • Wait is for an object locked by a synchronized block, while sleep is for a thread.

Thread safety requires several basic characteristics

  • Atomicity: Related operations are not interrupted by other threads in the middle of the process, usually through a synchronization mechanism
  • Visibility: When a thread changes a shared variable, its status is immediately known to other threads. This is generally understood as reflecting thread-local state onto main memory. Volatile is responsible for ensuring visibility.
  • Order: ensure serial semantics in threads, avoid instruction rearrangement, etc.

The volatile keyword

Volatile variables are visible, ordered, and do not guarantee atomicity. Because of Java’s memory model, threads that make changes to a shared variable do not immediately synchronize the changes to memory, but instead save them to the thread’s local cache.

Variables decorated with the volatile keyword are immediately synchronized to main memory after a thread makes a change, making the change visible to other threads

The Synchronized keyword

  • Sychronized is a built-in lock in Java that restricts thread access to a code block or method
  • Sychronized modifies class methods, instance methods, and code blocks
  • To execute a sychronized method or code block, the thread first acquires the lock of the modified object. Only one thread can acquire the lock of an object at a time, and the same thread can acquire the lock of the same object multiple times (reentrant lock).
  • Sychronized does not respond to interrupts. When a thread is waiting for a lock, interrupt calls to that thread have no effect
  • Lock acquisition and release are implicit. Locks are acquired when entering sychronized blocks and released when leaving Sychronized blocks

Wait /notify methods of the Obejct class

  • Wait /notify are methods for thread synchronization
  • The wait method causes the current thread to relinquish monitoring of the calling object and to wait. Until notify or notifyAll is called (syntactically, but with exceptions)
  • The wait method of an object can be called multiple times. The notify method releases only one wait method randomly, regardless of the call order. The notifyAll method is called to release all wait calls
  • A thread that calls wait may interrupt or wake up falsely, causing the wait method to return without actually calling the notify method of the object. It is usually used with a Lock flag and loop

The difference between volatile and synchronized

  • Volatile essentially tells the JVM that the value of the current variable in the register (working memory) is indeterminate and needs to be read from main memory;
  • Synchronized locks the current variable so that only the current thread can access it and other threads are blocked.
  • Volatile can only be used at the variable level; Synchronized can be used at the variable, method, and class levels
  • Volatile only enables change visibility of variables, not atomicity. Synchronized can guarantee the change visibility and atomicity of variables
  • Volatile does not block threads; Synchronized can cause threads to block.
  • Volatile variables are not optimized by the compiler; Variables of the synchronized tag can be optimized by the compiler

Method to stop a thread

  • Methods that modify variables with the volatile keyword terminate
public static void main(String[] args) throws Exception{ KeyWordStopThread task = new KeyWordStopThread("arrom"); new Thread(task).start(); Thread.sleep(3000); task.isExit = true; } public class KeyWordStopThread implements Runnable{ private String name; public volatile boolean isExit = false; Public KeyWordStopThread(String name){this.name = name; } @Override public void run() { while (! isExit){ try { Thread.sleep(1000); System.out.println("thread:"+name+" runing"); } catch (InterruptedException e) { e.printStackTrace(); }} system.out.println (" thread terminates "); }}Copy the code
  • Terminate with interrupt

  • Terminate using the Stop method

    Threads can be forcibly terminated by using thread.stop() directly, but the stop method is dangerous, like abruptly powering down a computer instead of shutting it down as normal, and may have unexpected results. When thread.stop() is called, the thread that created the child thread raises a ThreadDeatherror error and releases any locks held by the child thread. In general, any block of code that locks is used to protect data consistency. If a call to Thread.stop () results in the sudden release of all locks held by the thread, the protected data may become inconsistent, and other threads may use the corrupted data. It can lead to some very strange application errors. Therefore, using the stop method to terminate a thread is not recommended.