Creation and use of Java multithreading

1, Method 1: inherit Thread class to create Thread

Steps:

  • 1. Inherit Thread class
  • 2. Rewrite the run() method
  • 3. Create thread subclass object
  • 4. Call the start() method to start the thread

Code example:

public class Creat_Thread {

    public static void main(String[] args) {
        MyThread myThread = new MyThread();// 3 Create subclasses
        myThread.start();// 4. Call start: ① start the thread, ② call the run() method
        // Problem 1: you cannot directly call the run() method to start the thread
        // Problem 2: the thread cannot be started repeatedly
        System.out.println("python");
    }
}

class MyThread extends Thread{// 1 inherit Therad class
    // 2 rewrite the run() method
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"-"+i);
        }
    }
}

practice:

/**
 - @author xhj
 - Topic: create two threads, one traversing cardinality within 100 and one traversing even number within 100
 */
public class Thread_test01 extends Thread{

    public static void main(String[] args) {
        // Creating threads using anonymous inner classes
        new Thread_test01(){
            // Override the run() method
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    if (i % 2 == 0){
                        System.out.println(Thread.currentThread().getName()+"--"+"Even numbers are:"+i);
                    }
                }
            }
        }.start();// Start the thread and call run()

        new Thread_test01(){
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    if (i % 2 != 0){
                        System.out.println(Thread.currentThread().getName()+"--"+"The cardinality is:"+i);
                    }
                }
            }
        }.start();
    }
}

Common methods of Thread class:

  • start(): starts the current thread and calls run()
  • run(): you usually need to override run() in the parent class to write the business code operations you want to perform
  • currentThread(): a static method that returns the thread executing the current code
  • getName(): get the name of the current thread
  • setName(): sets the name of the current thread
  • yield(): release the execution authority of the current cpu
  • join(): calling join() in thread a, the a thread will enter the blocking state. Only after thread b execution is completed, thread a will continue to execute.
  • stop(): force the end of the current thread
  • Sleep (long millitime): how many milliseconds does the current thread sleep and enter the blocking state
  • isAlive(): judge whether the current thread is alive

Set thread priority:
1. There are three default levels defined in the Java source code:
You can also set the level between 1 and 10. The higher the level, the higher the execution power of the cpu, but it is not 100% priority. Only those with high probability will execute first.

2. Gets and sets the priority of the thread
getPriority(): get the priority of the thread
setPriority(): sets the priority of the thread

2, Method 2: implement the Runnable interface to create a thread

Steps:

  • Create a class that implements the Runnable interface
  • Override run()
  • Create a Thread class and take the instance of the class that implements the Runnable interface as a parameter
  • Call start()

Code example:

/**
 * @author xhj
 * 1.Create a class that implements the Runnable interface
 * 2.Override run()
 * 3.Create a Thread class and take the instance of the class that implements the Runnable interface as a parameter
 * 4.Call start()
 */
public class Creat_Runnable {

    public static void main(String[] args) {
        myRunnable myRunnable = new myRunnable();
        Thread thread = new Thread(myRunnable); // 3. Create a Thread class and take the instance of the class that implements the Runnable interface as a parameter
        thread.start();  // 4. Call start()
    }
}

// 1. Create a class that implements the Runnable interface
class myRunnable implements Runnable{

    // 2. Rewrite run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

Why pass an instance of Runnable to Thread as a parameter?
Through source code discovery:

Here, the constructor of thread is used to create the thread class. Thread.start() calls run() of the Runnable interface implementation method

Comparison of two creation methods:
1. The inheritance Thread method has the limitation of single inheritance
2. The way to implement the Runnable interface is more suitable for multi-threaded data sharing (all run() methods are in one class)
Contact: through the source code, the Thread method also implements the Runnable interface and rewrites run()
The same point: both methods need to rewrite the run() method, and both write and execute the business code in run().
In actual development, Runnable is generally implemented.

3, Thread life cycle

In JDK, several Thread states are defined with Thread.State class. In order to realize multithreading, a new Thread object must be created in the main Thread. The java language uses the objects of Thread class and its subclasses to represent threads. In a complete life cycle, threads are usually created in the following five states:

  1. New: when the object of a Thread class or its subclass is declared and created, the new Thread object is in the new state.
  2. Ready: after the thread in the newly created state is started (), it will enter the thread queue and wait for the CPU time slice. At this time, it is ready to run, but it is not allocated to CPU resources.
  3. Run: when the ready thread is scheduled and obtains CPU resources, it enters the running state. The run() method defines the operation and function of the thread.
  4. Blocking: in a special case, when an I / O operation is suspended or executed artificially, give up CPU resources, temporarily terminate their own execution, and enter the blocking state.
  5. Death: the thread has completed all its work or the thread is forcibly terminated in advance or terminated due to an exception.

4, Thread safety issues

1. Take the ticket selling case as an example. When selling tickets, multiple windows sell 100 tickets. Due to the public data, there will be thread safety problems. For example, two tickets labeled 100 have been sold because thread A has started selling tickets of 100, but the execution has not been completed completely. At this time, thread B found that ticket No. 100 was still not sold in the warehouse, so it also began to sell ticket No. 100. So both windows are selling ticket No. 100. However, there is only one of the 100 tickets in total, so there is A thread safety problem.
code:

/**
 * @author xhj
 * Create three windows to buy tickets, a total of 100 tickets
 */
public class windows extends Thread {

    private static int ticket = 100;
    @Override
    public void run() {
        while (ticket > 0){
            System.out.println(Thread.currentThread().getName()+"Buying tickets...Ticket No.:"+ticket);
            ticket --;
        }
    }
}
class windowsTest{
    public static void main(String[] args) {
        windows windows01 = new windows();
        windows windows02 = new windows();
        windows windows03 = new windows();
        windows01.setPriority(Thread.MAX_PRIORITY);
        windows01.setName("Window 1");
        windows02.setName("Window 2");
        windows03.setName("Window 3");

        windows01.start();
        windows02.start();
        windows03.start();
    }
}


2. Solution: adopt the synchronization mechanism in Java to solve the thread safety problem

Solution 1: synchronize code blocks
Using the synchronized keyword
code:

package Creation and use of multithreading.Ticket buying cases;

/**
 * @author xhj
 * Create three windows to buy tickets, a total of 100 tickets
 */

/*
    synchronized(Synchronization monitor){
        // Code to be synchronized
        }
Note: 1. The code for operating shared data is the code that needs to be synchronized
      2.Shared data: variables operated by multiple threads. For example, a ticket is sharing data.
      3.Synchronization monitor, commonly known as lock. The object of any class can act as a lock.
      Requirement: multiple threads must share the same lock.
*/
public class windows extends Thread {

    private static int ticket = 100;
  	private static Object object =  new Object();           //All threads must use the same lock
    @Override
    public void run() {
            while (ticket > 0){
                synchronized (object){                  //Lock
                    if (ticket > 0) {
                        System.out.println(Thread.currentThread().getName()+"Buying tickets...Ticket No.:"+ticket);
                        ticket --;
                    }
            }
        }

    }
}
class windowsTest{
    public static void main(String[] args) {
        windows windows01 = new windows();
        windows windows02 = new windows();
        windows windows03 = new windows();
        windows01.setPriority(Thread.MAX_PRIORITY);
        windows01.setName("Window 1");
        windows02.setName("Window 2");
        windows03.setName("Window 3");

        windows01.start();
        windows02.start();
        windows03.start();
    }
}

Solution 2: synchronization method
Use the synchronized keyword on the method
code:

package Creation and use of multithreading.Ticket buying cases;

/**
 * @author xhj
 * Create three windows to buy tickets, a total of 100 tickets
 */

/*
  Synchronization method: add the synchronized keyword to the method
*/
public class windows_ extends Thread {

    private static int ticket = 100;

    @Override
    public void run() {
        while (true){
             show();
        }
    }
    
    public static synchronized void show(){  // Synchronization method
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName()+"Buying tickets...Ticket No.:"+ticket);
                ticket --;
            }
        }
    }
class windowsTest_{
    public static void main(String[] args) {
        windows_ windows01 = new windows_();
        windows_ windows02 = new windows_();
        windows_ windows03 = new windows_();
        windows01.setPriority(Thread.MAX_PRIORITY);
        windows01.setName("Window 1");
        windows02.setName("Window 2");
        windows03.setName("Window 3");

        windows01.start();
        windows02.start();
        windows03.start();
    }
}

Summary of synchronization methods:
1. The synchronization method still involves the synchronization monitor, but we don't need to explicitly declare it.
2. Non static synchronization method. The synchronization monitor is this static synchronization method. The synchronization monitor is the current class itself.

thread deadlock
1. Understanding of Deadlock: different threads occupy the synchronization resources required by the other party and do not give up. They are waiting for the other party to give up the synchronization resources they need, forming a thread deadlock.
2. Description:
1) After a deadlock occurs, there will be no exception or prompt, but all threads are blocked and cannot continue.
2) When we use synchronization, we should avoid deadlock.

Three ways to solve thread safety problems:
1. Use lock lock, private ReentrantLock lock = new ReentrantLock();
code:

package Creation and use of multithreading;

import java.util.concurrent.locks.ReentrantLock;

/**
 * Resolve thread deadlock
 * @author xhj
 */
public class Thread_Lock {

    public static void main(String[] args) {

        Windows windows = new Windows();
        Thread thread1 = new Thread(windows);
        Thread thread2 = new Thread(windows);
        Thread thread3 = new Thread(windows);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class Windows implements Runnable{

    private static int ticket = 100;
    private static ReentrantLock lock = new ReentrantLock();// Create lock object instance
    //private ReentrantLock lock = new ReentrantLock(true);//  The parameter is false by default. When it is true, it is a fair lock. That is, the first in, first out principle.
    @Override
    public void run() {

        while (true){
            try {
                // Call lock() to lock
                lock.lock();
                if (ticket > 0){
                    System.out.println(Thread.currentThread().getName()+": "+ticket);
                    ticket--;
                }else break;
            }finally {
                // Unlock
                lock.unlock();
            }
        }
    }
}

lock() and unlock() are used to lock and unlock the code blocks that need to solve security problems. When locking, other threads cannot enter. After unlocking, other threads can enter. Note: remember to unlock after locking.

Interview question: what are the similarities and differences between synchronized and Lock?

  • Same: both can solve thread safety problems
  • Difference: the synchronized mechanism automatically releases the synchronization monitor after executing the corresponding synchronization code.
    Lock requires manual start synchronization (Lock()) and manual end synchronization (unLock())

Interview question: what are the similarities and differences between sleep() and wait()?

  • The same point: after execution, the current thread can enter the blocking state.
  • difference:
    • 1) The positions of the two method declarations are different: sleep() declared in Thread class and wait() declared in Object() class
    • 2) The requirements for calling are different: sleep() can be called in any required scenario. wait() must be used in the synchronization code block.
    • 3) About whether to release the synchronization monitor: if both methods are used in the synchronization code block or synchronization code method, sleep() will not release the lock, and wait() will release the lock.

5, Method 3: implement Callable interface

  • The Callable method is more powerful than the Runable method
  • Compared with the run () method, you can have a return value
  • Method can throw an exception
  • Return values that support generics
  • You need to use the FutureTask class, such as getting the returned results

What is the Future interface?

  • You can cancel the execution results of your specific Runnable and Callable interface tasks, query whether they are completed, obtain results, etc.
  • FutureTask is the only implementation class of Futrue interface
  • FutureTask implements both Runnable and Future interfaces. It can be executed by the thread as Runnable or get the return value of Callable as Future.

Specific steps:

  • 1. Implement the Callable interface and rewrite the call method
  • 2. Create an object of a class that implements the Callable interface in the main method
  • 3. Create the FutureTask class and pass the object that implements the method of the Callable interface
  • 4. Create the Thread class to start the Thread
  • 5. Use the future.get method to get the results (do not write if not needed)

Case:
Create a thread to realize the accumulation of 1-100:

package Creation and use of multithreading;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author xhj
 * The third way to create a thread is to implement the Callable interface
 * 1,Implement the Callable interface and rewrite the call method
 * 2,Create an object of a class that implements the Callable interface in the main method
 * 3,Create the FutureTask class and pass the object of the method implementing the Callable interface as the parameter
 * 4,Create the Thread class to start the Thread
 * 5,Use the future.get method to get the results (do not write if not needed)
 */
public class ThreadNew {

    public static void main(String[] args) {
        NumThread numThread = new NumThread();//Create a class that implements the Callable interface
        FutureTask futureTask = new FutureTask(numThread);//Create FutureTask class, and use this class to get the returned results

        new Thread(futureTask).start();//Start thread

        try {

            Object sum = futureTask.get();   //Get results

            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}

class NumThread implements Callable {

    @Override
    public Object call() throws Exception {

        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum = i + sum;
            System.out.println(i);
        }
        return sum;//Return results
    }
}

6, Mode 4: use thread pool


Case:

package Creation and use of multithreading;

import java.util.concurrent.*;

/**
 * @author xhj
 *  Four ways to create threads: using thread pool
 *  
 *
 */
public class ThreadPool {

    public static void main(String[] args) {

        //1. The number of threads in the specified thread pool is 10
        ExecutorService service = Executors.newFixedThreadPool(10);
        
        //2. Pass thread as parameter
        service.submit(new NumberThread1());   //The submit method is applicable to the thread created by Callable

        NumberThread2 numberThread2 = new NumberThread2();
        
        FutureTask<Integer> futureTask = new FutureTask<Integer>(numberThread2);
        service.execute(futureTask);    //The execute method is applicable to the threads created by Runnable and Thread

        service.shutdown();  //3. Close the thread pool and free up resources
    }
}

class NumberThread1 implements Runnable{

    //Traverse even numbers within 100
    @Override
    public void run() {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + "==" + i);
                sum = i + sum;
            }
        }
    }
}

class NumberThread2 implements Callable {


    //Traverse odd numbers within 100
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + "==" + i);
                sum = i + sum;
            }
        }
        return sum;
    }
}

Keywords: Java

Added by Lijoyx on Tue, 07 Sep 2021 04:57:14 +0300