Predecessors planted trees and posterity enjoyed the cool: Java multithreading in simple terms

Keywords: Java Multithreading

1. Thread overview

1.1 threads and processes

  • Process is a program in the running process and has certain independent functions
  • Concurrency: only one instruction can be executed at a time, but multiple process instructions are executed in rapid rotation
  • Parallelism: multiple instructions are executed simultaneously on multiple processors
  • A thread is the execution unit of a process

1.2 advantages of multithreading

  • Memory cannot be shared between processes, but it is very easy between threads
  • When the system creates a process, it needs to reallocate system resources for the process, but the cost of creating a thread is much less, so using multithreading is more efficient
  • The Java language has built-in multithreading

2. Thread creation and startup

2.1 inherit Thread

public class FirstThread extends Thread {
    private int i;

    @Override
    public void run() {
        for(i = 0; i < 50; i ++){
            System.out.println(this.getName() + "" + i);
        }
    }

    public static void main(String[] args){
        FirstThread ft = new FirstThread();
        for(int i =0; i < 100;i ++){
            System.out.println(Thread.currentThread().getName() + "" + i);
            if(i == 20) {
                ft.run();
            }
        }
    }
}

2.2 implementation of Runnable interface

public class FirstThread implements java.lang.Runnable {
    private int i;

    public void run() {
        for(i = 0; i < 50; i ++){
            System.out.println(Thread.currentThread().getName()+ "" + i);
        }
    }

    public static void main(String[] args){
        FirstThread ft = new FirstThread();
        for(int i =0; i < 100;i ++){
            System.out.println(Thread.currentThread().getName() + "" + i);
            if(i == 20) {
                ft.run();
            }
        }
    }
}

2.3 using Callable and Future

  • The Callable interface provides a call() method that can be used as the thread execution body. The call() method has a return value and can declare to throw an exception
  • Java 5 provides a Future interface to represent the return value of the call() method in the Callable interface, and provides a futureask implementation class for the Future interface
  • Methods defined by Future interface:
Method nameeffect
boolean cancel(boolean mayInterruptIfRunning)Attempt to cancel the associated Callable task in the Future
V get()Returns the return value of the call method in the Callable task. This method will cause thread blocking and can only be obtained after the sub thread is executed
V get(long timeout, TimeUnit unit)Returns the return value of the call method in the Callable task. This method allows the program to block the time specified by timeout and unit at most. If the Callable task has not returned a value after the specified time, a TimeoutException exception will be thrown
boolean isCancelled()Cancel the task in Callable
boolean isDone()Is the task in Callable completed

public class CallableDemo {
    public static void main(String[] args){
        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
            int i = 0;
            for( ; i < 100; i++){
                System.out.println(i);
            }
            return i;
        });
        new Thread(task).start();
        try {
            System.out.println(task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

2.4 comparison of three ways to create threads

Advantages and disadvantages of Runnable and Callable:

  • Thread class only implements Runnable and Callable interfaces, and can inherit other classes
  • In the case of Runnable and Callable, multiple threads can share the same target object, so it is very suitable for multiple threads to process the same resource
  • Programming is slightly more complex, and if you need to access the current thread, you must use Thread.currentThread()

Thread strengths and weaknesses:

  • Thread class already inherits thread class, so it cannot inherit other parent classes
  • The writing is simple. If you need to access the current thread, use this

3. Thread life cycle

3.1 new and ready status

  • The new statement is only allocated memory by the Java virtual machine, and does not show the dynamic characteristics of any thread
  • If the run method of the inherited class is called directly, there will only be MainActivity, and the name of the current execution thread cannot be obtained through getName, but Thread.currentThread().getName()
  • After calling the run method, the thread is no longer in the new state

3.2 operation and blocking status

  • When the number of threads is greater than the number of processors, multiple threads rotate on the same CPU
  • Cooperative scheduling strategy: only when a thread calls the sleep() or yield() method will it give up the occupied resources -- that is, the thread must actively give up the occupied resources
  • Preemptive scheduling strategy: the system allocates a small period of time to each executable thread to process the task. When the task is completed, the system will deprive the resources occupied by the thread
  • The blocked thread will re-enter the ready state at the appropriate time

Thread state transition diagram

3.3 death status

  • Test thread death available isAlive()
  • The thread in death cannot run again, otherwise an IllegalThreadStateException will be thrown

4. Control thread

4.1 join thread

  • If A.join() is called by MainActivity, MainActivity will be blocked. MainActivity will not execute until thread A finishes executing

4.2 daemon thread

  • If all foreground threads die, the background thread will die automatically
public class DaemonThread extends Thread {
    @Override
    public void run() {
        for(int i = 0; i< 1000; i++){
            System.out.println("DaemonActivity" + i);
        }
    }

    public static void main(String[] args){
        DaemonThread thread = new DaemonThread();
        thread.setDaemon(true);
        thread.start();
        for(int i = 0; i < 10; i ++ ){
            System.out.println("MainActivity" + i);
        }
    }
}

Operation results

4.3 thread sleep

 try {
      Thread.sleep(200);
} catch (InterruptedException e) {
       e.printStackTrace();
}
  • After the sleep method pauses the current thread, it will give other threads execution opportunities, regardless of other thread priorities; However, the yield method will only be given to threads with the same or higher priority
  • The sleep method will enter the blocking state and will not enter the ready state until the blocking time has elapsed; yield forces the current thread to a ready state
  • The sleep method threw an InterruptedException, while the yield method did not throw an exception

4.4 changing thread priority

  • High priority threads get more execution opportunities, and low priority threads get less execution opportunities
  • setPriority and getPriority methods to set and return the priority of the specified thread

5. Thread synchronization

  • The run() method does not have synchronization security
  • java introduces synchronization monitor to solve the problem of multithreading synchronization. In synchronized (obj), obj is a shared resource

5.1 synchronization method

  • Synchronous method is to use synchronized to modify a method
  • The synchronization monitor of the instance method defaults to this
  • In Java, immutable classes are always thread safe. Variable class objects need additional methods to ensure their thread safety

public class DaemonThread extends Thread {

    static int balance = 100;
    int drawAmount;
    String name;

    public DaemonThread(int drawAmount, String name){
        this.drawAmount = drawAmount;
        this.name = name;
    }

    @Override
    public void run() {
        this.draw(drawAmount);
    }

    public synchronized void draw(int amount){
        if(balance  >= amount){
            System.out.println(this.name + "Take it out" + amount);
            try{
                Thread.sleep(1);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
            balance -= amount;
            System.out.println("\t The balance is" + balance);

        } else{
            System.out.println(this.name + "Cash withdrawal failed");
        }
    }
    public static void main(String[] args){
        new DaemonThread(50, "A").start();
        new DaemonThread(100, "B").start();
    }
}

5.2 release the lock of the synchronization monitor

In the following cases, the thread releases the lock on the synchronization monitor

  • The execution of the synchronization method and synchronization code block of the current thread ends
  • Encountered break and return
  • Exception encountered
  • The program executes the wait() method of the synchronization monitor object

It will not be released under the following conditions:

  • When the synchronization method is executed, the program calls the Thread.sleep() Thread.yield() method
  • Another thread called the thread's suspend method

5.3 synchronization lock

  • Starting with Java 5, a more powerful synchronization lock mechanism is provided, which can be achieved by explicitly defining synchronization lock objects
  • Lock provides a wider range of locking operations than synchronized, and supports multiple related Condition objects
  • Lock type:
    Lock
    ReadWriteLock
    ReentrantLock: commonly used. You can re lock a locked object
    ReentrantReadWriteLock
    StampedLock
Method nameeffect
lockLock
unlockUnlock

5.4 deadlock

A et al. B, B et al. A

5.5 thread communication

5.5.1 traditional thread communication

Method nameeffect
waitCauses the current thread to wait until another thread calls the notify() or notifyAll() methods of the synchronization monitor
notifyWake up a single thread waiting on this synchronization monitor
notifyAllWake up all threads waiting on this synchronization monitor
  • wait() must be executed with a lock

5.5.2 using Condition

  • If synchronized is not applicable in the system to ensure thread synchronization, but Lock object is used to ensure synchronization, then wait, notify, notifyAll() cannot be used for thread communication
  • When using Lock objects, Java provides conditions to ensure thread coordination
  • The Condition method is as follows
Method nameeffect
awaitCauses the current thread to wait until another thread calls the signal() or signalAll() methods of the synchronization monitor
signalWake up a single thread on this Lock object
signalAllWake up all threads on this Lock object

5.5.3 using blocking queues

  • Java provides a BlockingQueue interface
  • When the producer thread attempts to put elements into the BlockingQueue, if the queue is full, the thread is blocked; When a consumer thread attempts to fetch an element from a BlockingQueue, if the queue is empty, the thread is blocked
Method nameeffect
put(E e)Try putting the E element into the BlockingQueue
take()Attempt to fetch an element from the BlockingQueue header

public class BlockingQueueThread extends Thread {

    private BlockingQueue<String> bq;

    public BlockingQueueThread(BlockingQueue<String> bq){
        this.bq = bq;
    }

    @Override
    public void run() {
        String[] strColl = new String[]{
                "Java",
                "Kotlin",
                "JavaScript"
        };



        for(int i = 0; i < 1000; i ++){
            try {
                System.out.println(getName() + "Start work" + i);
                bq.put(strColl[i % 3]);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println(getName() + "end-of-job");
    }

    public static void main(String[] args){
        BlockingQueue<String> bq = new ArrayBlockingQueue<>(5);
        new BlockingQueueThread(bq).start();
    }
}

Result display

It can be seen that Thread-0 has been blocked when it runs for the sixth time, and content cannot be added to it

6. Thread groups and unhandled exceptions

  • ThreadGroup refers to thread group, which can classify and manage a batch of threads
  • The child thread is in the same thread group as the parent thread that created it
  • ThreadGroup method
Method nameeffect
int activeCountReturns the number of active threads in the thread group
interruptInterrupts the number of all active threads in this thread group
isDaemonIs the thread group a background thread group
setDaemonSet background thread
setMaxPrioritySets the highest priority for the thread group

7. Thread pool

  • The thread pool creates a large number of idle threads when the system starts
  • The program passes a Runnable object or Callable object to the thread pool, and the thread pool starts a free thread to execute them
  • The end of the thread does not die, but returns to the idle state
  • After Java 8, an Executors factory class was added to produce thread pools

7.1 ThreadPool

public class ThreadPoolTest {

    public static void main(String[] args){
        ExecutorService pool = Executors.newFixedThreadPool(2);

        java.lang.Runnable target = () -> {
           for (int i = 0; i < 100 ; i ++){
               System.out.println(Thread.currentThread().getName() + "of i by" +i);
           }
        };

        pool.submit(target);
        pool.submit(target);
        pool.shutdown();
    }
}

Result display

7.2 ForkJoinPool

  • Split a task into multiple small tasks for parallel calculation, and then combine the results of multiple small tasks into the total calculation results
  • ForkJoinPool is the implementation class of ExecutorService
public class PrintTask extends RecursiveAction {

    public static int THREADSH_HOLD = 50;

    private int start;

    private int end;

    public PrintTask(int start, int end){
        this.start = start;
        this.end = end;
    }

    @Override
    protected void compute() {
        if(end - start < THREADSH_HOLD){
            for(int i = start; i < end; i ++){
                System.out.println(Thread.currentThread().getName() + "of i by" + i);
            }
        } else {
            PrintTask left = new PrintTask(start, (start + end) / 2);
            PrintTask right = new PrintTask((start + end) / 2 , end);
            left.fork();
            right.fork();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        PrintTask printTask = new PrintTask(0 , 300);
        ForkJoinPool pool = new ForkJoinPool();
        pool.submit(printTask);
        pool.awaitTermination(2, TimeUnit.SECONDS);
        pool.shutdown();

    }
}

Result display  

  This is a small series to prepare some information for you

 

Code scanning and wechat for free!

Posted by CBG on Tue, 19 Oct 2021 20:13:33 -0700