Java improvement class (I) thread explanation

1、 Overview

Before learning thread, let's first understand the relationship between threads and processes:

From the above description, we can know that thread is the basic scheduling unit of CPU. Only by making good use of multithreading can we make full use of the multi-core resources of CPU.

This article is based on JDK 8 (also known as JDK 1.8).

2、 Thread usage

2.1 start thread

There are four ways to create threads:

2.1. 1. Creation method of runnable

public class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
Thread thread = new Thread(new MyThread());
thread.start();

2.1. 2. Inherit thread creation method

public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
MyThread thread = new MyThread();
thread.start();

The above code can be written in a simpler way, as follows:

Thread thread = new Thread(){
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
};
thread.start();

2.1. 3 lambda creation method

new Thread(()-> System.out.println(Thread.currentThread().getName())).start();

2.1. 4 using callable and future

From the source code, we can know that the parent class of thread is runnable and jdk1 0, and callable is similar to runnable, which is jdk1 5 makes up for the situation that the calling thread does not return a value. It can be regarded as a supplement to runnable. Let's take a look at the implementation of callable.

public class MyThread implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        return Thread.currentThread().getName();
    }
}
Callable<String> callable = new MyThread();
FutureTask<String> ft = new FutureTask<>(callable);
new Thread(ft,"threadName").start();
System.out.println(ft.get());

2.1. 5. The difference between run() and start()

It is the start () method that really starts the thread, not run (). Like ordinary member methods, run () can be reused, but it cannot start a new thread.

2.2 common methods of thread

Thread class method

Thread static method

2.3 difference between sleep() and wait()

Sleep is a thread method and wait is an object method. Their functions are similar. The most essential difference is that sleep does not release the lock and wait releases the lock.

Different usage: sleep (milliseconds) can wake him up automatically by specifying the time. If the time is less than, you can only call interreput () to terminate the thread; Wait() can be called directly with notify() / notifyall().

Key points: the code for testing the lock release of wait and sleep is as follows:

public class SynchronizedTest extends Thread {
    int number = 10;
    public synchronized void first(){
        System.out.println("this is first!");
        number = number+1;
    }
    public synchronized void secord() throws InterruptedException {
        System.out.println("this is secord!!");
        Thread.sleep(1000);
//        this.wait(1000);
        number = number*100;
    }
    @Override
    public void run() {
        first();
    }
}
SynchronizedTest synchronizedTest = new Synchronizedtest();
synchronizedTest.start();
synchronizedTest.secord();
// 主线程稍等10毫秒
Thread.sleep(10);
System.out.println(synchronizedTest.number);

According to the results:

Summary: using sleep (1000) does not release the synchronization lock, execute 10 * 100 + 1 = 1001, wait (1000) releases the lock, and the execution order is (10 + 1) X100 = 1100, so sleep does not release the lock, wait releases the lock.

3、 Thread state

3.1 thread status overview

Thread status:

The status of the thread can be viewed using getstate(). For more status details, see the thread source code, as shown in the following figure:

3.2 implementation of thread status code

3.2. 1 new has not been started

Thread thread = new Thread() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
};
// 只声明不调用start()方法,得到的状态是NEW
System.out.println(thread.getState()); // NEW

3.2. 2 runnable running status

Thread thread = new Thread() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
};
thread.start();
System.out.println(thread.getState()); // RUNNABLE

3.2. 3 blocked

The synchronized synchronization blocking is implemented. The code is as follows:

public class MyCounter {
    int counter;
    public synchronized void increase()  {
        counter++;
        try {
            Thread.sleep(10*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
MyCounter myCounter = new MyCounter();
// 线程1调用同步线程,模拟阻塞
new Thread(()-> myCounter.increase()).start();
// 线程2继续调用同步阻塞方法
Thread thread = new Thread(()-> myCounter.increase());
thread.start();

// 让主线程等10毫秒
Thread.currentThread().sleep(10);
// 打印线程2,为阻塞状态:BLOCKED
System.out.println(thread.getState());

3.2. 4 waiting permanent waiting state

public class MyThread extends Thread{
    @Override
    public void run() {
        synchronized (MyThread.class){
            try {
                MyThread.class.wait();
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
Thread thread = new Thread(new MyThread());
thread.start();
// 主线程挂起200毫秒,等thread执行完成
Thread.sleep(200);
// 输出WAITING,线程thread一直处于被挂起状态
System.out.println(thread.getState());

Wake up thread: the notify / notifyAll method can be used. The code is as follows:

synchronized (MyThread.class) {
    MyThread.class.notify();
}

Method to make thread waiting:

You can know the join method of thread by viewing the thread source code. The bottom layer uses the wait implementation of object, as shown in the following figure:

Note: looking at the source code of the object, we can see that wait() does not pass parameters, which is equivalent to wait (0). The set "0" is not executed immediately, but waits indefinitely, not executed, as shown in the following figure:

3.2. 5 TIMED_ Waiting timeout wait state

TIMED_ In the waiting status, you only need to set the time for the wait. The code is as follows:

public class MyThread extends Thread{
    @Override
    public void run() {
        synchronized (MyThread.class){
            try {
                MyThread.class.wait(1000);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

The calling code is the same as follows:

Thread thread = new Thread(new MyThread());
thread.start();
// 主线程挂起200毫秒,等thread执行完成
Thread.sleep(200);
// 输出TIMED_WAITING
System.out.println(thread.getState());
synchronized (MyThread.class) {
    MyThread.class.notify();
}

3.2. 6 terminated status

Thread thread = new Thread(()-> System.out.println(Thread.currentThread().getName()));
thread.start();
// 让主线程等10毫秒
Thread.currentThread().sleep(10);
System.out.println(thread.getState());

4、 Deadlock

According to the previous knowledge, we know that the lock is not released when using sleep, so we can easily write deadlock code by using this feature. The specific process is shown in the figure (the picture comes from teacher Yang Xiaofeng's article):

The code is as follows:

static  Object object1 = new Object();
static  Object object2 = new Object();

public static void main(String[] args) {

    Thread thread = new Thread(){
        @Override
        public void run() {
            synchronized (object1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (object2){
                    System.out.println(Thread.currentThread().getName());
                }
            }
        }
    };

    Thread thread2 = new Thread(){
        @Override
        public void run() {
            synchronized (object2){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (object1){
                    System.out.println(Thread.currentThread().getName());
                }
            }
        }
    };

    thread.start();
    thread2.start();

Run the above code and the program will be waiting indefinitely.

5、 Summary

According to the above content, we have systematically learned the use of thread, but learning without thinking is useless. Finally, let's leave a question: according to the knowledge introduced in this article, how can deadlock be avoided? (ha ha, sell a pass. You can get the answer according to the combination of knowledge points in the article)

Source code download: https://github.com/vipstone/java-core-example.git

Recommendation part

I recently read the course of Yang Xiaofeng, former chief engineer of Oracle, who is also the owner of the flow chart cited in the fourth part. I feel very good. I recommend it to you. Let's learn the Java core systematically.

Reference documents

https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.State.html

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>