multithreading

The JVM allows the creation of multiple threads, which are represented by the java.lang.Thread class

Create a way

There are four ways to create a multithread:

  • Inherits from Thread
  1. Create a subclass that extends from Thread

  2. Override the run() method of the Thread class

  3. Create an object for a subclass of Thread

  4. Call the object’s start() method

class MyThread extends Thread{
    @Override
    public void run(a) {
        for (int i = 0; i < 100; i++) { System.out.println(i); }}}public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();// Start the thread and call the run method
        // The following code is still executed in the main thread
        System.out.println("hello"); }}Copy the code

Threads that have already been started cannot be started again. The main Thread is obtained from thread.currentThread

  • Write classes to implement the Runabble interface
  1. Create a class that implements the Runabble interface

  2. Implement the abstract method Run() in Runabble

  3. Create an object that implements the class

  4. Pass this object to the constructor of class Thread to create an object of class Thread

  5. The start() method is called from an object of class Thread

class MyThread implements Runnable{
    @Override
    public void run(a) {
        System.out.println("111"); }}public class Test {
    public static void main(String[] args) {
        MyThread my=new MyThread();
        Thread thread1=new Thread(my);
        Thread thread2=newThread(my); thread1.start(); thread2.start(); }}Copy the code

Comparison of the two methods:

The way to implement the Runabble interface is a priority in development. Why: Runabble doesn’t have the limitation of single inheritance and is more suitable for situations where multiple threads share data

Two new creation methods:

  • Implements the Callable interface
//1. Create an implementation class that implements the Callable interface
class MyThread implements Callable {
    //2. Implement the Call method and declare the operation that this thread needs to perform in the Call method
    @Override
    public Object call(a) throws Exception {
        int sum = 0;
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
            sum += i;
        }
        returnsum; }}public class Test {
    public static void main(String[] args) {
        //3. Create an object for the Callable interface implementation class
        MyThread mt = new MyThread();
        //4. Pass an object from the Callable interface implementation class as a parameter to the FutureTask constructor and create a FutureTask object
        FutureTask ft = new FutureTask(mt);
        //5. Pass the FutureTask object as an argument to the Thread constructor and call start().
        new Thread(ft).start();
        try {
            //FutureTask's get() returns the value of the overwritten Call() method on the Callable object of the constructor parameter
            Object sum = ft.get();
            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch(ExecutionException e) { e.printStackTrace(); }}}Copy the code
  • Using thread pools

Create a number of threads in advance and put them into the thread pool, which can be directly obtained when using, and put back into the pool after using, avoiding frequent creation and destruction, and can be reused.

class MyThread implements Runnable {
    @Override
    public void run(a) {
        for (int i = 0; i < 10; i++) { System.out.println(i); }}}public class Test {
    public static void main(String[] args) {
        //1. Provide a specified number of thread pools
        ExecutorService service = Executors.newFixedThreadPool(10);
        //2. Provide an object that implements a Runnable interface or a Callable interface
        MyThread myThread = new MyThread();
        service.execute(myThread);// Apply to Runnable
        service.submit(myThread);// Apply to Callable

        service.shutdown();// Close the thread pool}}Copy the code
Common methods of the Thread class

Thread priority

For threads with the same priority, resources are allocated in queue mode. For threads with high priority, resources are allocated in preemptive mode

By getPriority () to check the Thread or Thread priority. CurrentThread. SetPriority () set priority, high priority Thread has a high probability of lower priority Thread. The default priority is 5

The life cycle of the thread

Thread lifecycles include the following five types:

Solve thread safety issues

When multiple threads operate on shared data, security problems will occur. The main solutions are as follows:

  1. Synchronized block
synchronized(Sync monitor){// Code that needs to be synchronized;
}
Copy the code

A synchronization monitor is also known as a lock. An object of any class can act as a lock, and multiple threads must use the same lock. For multiple threads that inherit Thread, the lock needs to be set to the class name.class; For multithreading that implements Runabble’s methods, the lock can be any Object, such as Object obj

Limitations: Only one thread can participate in the operation of the synchronized code block, making it single-threaded and inefficient

  1. Synchronized methods

If the code that operates on shared data is all declared in the same method, declare the method directly as synchronous

public synchronized void show(a){// Synchronize monitor this
    // Code that needs to be synchronized;
}
Copy the code

When this is used, the default synchronization monitor is this. For multiple threads that inherit Thread, we need to make the synchronization method static again, so that the synchronization monitor for multiple objects is the same. For multithreads that implement Runabble’s methods, simply call the synchronous function directly in run()

  1. The Lock Lock

The LOCk interface is provided in the JDK and its implementation class, Reentrantlock, is provided

class MyThread implements Runnable {
    private int tickets = 100;
    //1. Instantiate the Reentrant Lock object
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run(a) {
        while (true) {
            try {
                //2. Call the lock() method
                lock.lock();
                if (tickets > 0) {
                    System.out.println(Thread.currentThread().getName() + "" + tickets);
                    tickets--;
                } else {
                    break; }}finally {
                //3. Invoke the unlock methodlock.unlock(); }}}}Copy the code

Synchronized and synchronized

Can solve thread safety issues

Different: synchronized releases the synchronization monitor automatically after the synchronization code is executed, and lock needs to manually start synchronization and release synchronization

To solve the deadlock

Different threads occupy the synchronization resources required by each other and do not give up. They are waiting for each other to give up the synchronization resources needed by them, resulting in a deadlock

The solution:

  • Special measures and principles
  • Minimize the definition of synchronized resources
  • Try to avoid synchronous nesting
Thread communication

Wait (): Once this method is executed, the current thread enters the blocked state and releases the synchronization monitor so that other threads can pick up the synchronization monitor and execute the synchronization method

Notify (): Once this method is executed, it wakes up the wait threads or, if there are more than one, the thread with the highest priority

NotifyAll (): Upon execution of this method, all wait threads are awakened

The above three methods can only be called in a synchronized method or synchronized code block, and the caller of the three methods must be a synchronization monitor in the synchronized code block or synchronized method

The difference between sleep and wait

Both block threads

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Sleep can be called anywhere, while WAIT can only be called in a synchronized block or method. 3) When both are used in a synchronized block or method, sleep does not release the synchronization monitor, while WAIT does