java basics thread

The difference between throw and throws

Throw, acting inside the method, is used to actively throw exceptions
throws, which acts on the method declaration. Declaring the method may throw some exceptions

For the exception handling method in the project, we generally throw it up layer by layer, and finally handle it uniformly through the exception handling mechanism (display the exception page or return the unified json information). Custom exceptions generally inherit RunntimeException. Let's take a look at Hibernate and other frameworks. Their exception system is finally inherited from RunntimeException

How threads are created
We often say it in the following three ways:

inherit Thread
 realization Runable Interface
 realization Callable Interface (you can get the return value after thread execution)

However, in the latter two cases, a more accurate understanding is to create an executable task, which should be executed in a multi-threaded manner,

It also needs to be executed by creating a Thread object, such as new Thread (New runnable() {}) start(); In this way.

In actual development, we usually use Thread pool to complete the creation of Thread and better manage Thread resources.

Case: how to start the thread correctly

 class MyThread extends Thread{
@Override
public void run() {
    System.out.println(Thread.currentThread().getName()+": running.....");
}

}

 public static void main(String[] args){
    MyThread thread = new MyThread();
    //How to start the thread correctly
    //thread.run();// Calling a method does not open a new thread
    thread.start();

}

Case: implementing runnable only creates an executable task, not a thread

class MyTask implements Runnable{

@Override
public void run() {
    System.out.println(Thread.currentThread().getName()+":running....");
}

}

public static void main(String[] args){
    MyTask task = new MyTask();
    //task.start(); // It cannot be started directly as a thread
    //It expresses a task that needs to start a thread to execute
    new Thread(task).start();
}

Case 3: runnable vs callable

class MyTask2 implements Callable{

@Override
public Boolean call() throws Exception {
    return null;
}

}

To be clear:

In essence, the way to create a Thread is to inherit the Thread, which is the Thread pool. The internal Thread object is also created to execute the task

Is the execution of an ordinary main method in single thread mode or multi thread mode? Why?

Because java has an important feature called automatic garbage collection mechanism, the answer is multithreading. There are two parts: main thread (user thread) and garbage collection thread GC (guard thread).

What is deadlock

Deadlock, philosopher's problem.

The scenario of switching to thread is that thread a holds exclusive lock resource a and attempts to obtain exclusive lock resource b

Meanwhile, thread B holds exclusive lock resource B and attempts to acquire exclusive lock resource a

In this way, thread A and thread B hold the lock required by each other, resulting in blocking and eventually deadlock.

public class Deadlock {

private static final Object a = new Object();
private static final Object b = new Object();

public static void main(String[] args){
    new Thread(new Task(true)).start();
    new Thread(new Task(false)).start();
}

static class Task implements Runnable{
    private boolean flag;

    public Task(boolean flag){
        this.flag = flag;
    }

    @Override
    public void run() {
        if(flag){
            synchronized (a){
                System.out.println(Thread.currentThread().getName()+"->Get a resources");
                synchronized (b){
                    System.out.println(Thread.currentThread().getName()+"->Get b resources");
                }
            }
        }else{
            synchronized (b){
                System.out.println(Thread.currentThread().getName()+"->Get b resources");
                synchronized (a){
                    System.out.println(Thread.currentThread().getName()+"->Get a resources");
                }
            }
        }

    }
}
 }

 //There may be deadlock. If the first thread has finished and the second thread obtains the execution permission, there will be no deadlock

2. How to prevent deadlock? (key points)

Reduce synchronous code block nesting

Reduce the use granularity of locks, and do not share a lock for several functions

Try to use the method of tryLock (timeout) as much as possible. You can set the timeout time, so that after the timeout, you can actively exit to prevent deadlock (key)

Four conditions satisfied by deadlock
Mutually exclusive, inalienable, cyclic waiting, request and hold

Necessary conditions for deadlock generation:

Mutually exclusive condition: the process requires exclusive control of the allocated resources, that is, a resource is occupied by only one process in a period of time.
Request and hold condition: when the process is blocked due to the request for resources, keep the obtained resources.
Conditions of non deprivation: the resources obtained by the process cannot be deprived before they are used up, and can only be released by themselves when they are used up.
Loop waiting condition: when a deadlock occurs, there must be a loop chain of process resources.

The difference between Sleep and wait

1. Different categories:

sleep Method is defined in Thread upper
wait Method is defined in Object upper

2. The processing methods of lock resources are different

sleep The lock will not be released
wait The lock will be released

3. Scope of application:

sleep Can be used in any code block
wait Must be executed in a synchronization method or synchronization code block

4. Methods used together with wait

void notify()

Wakes up a single thread that is waiting on this object's monitor.
Wake up a single thread waiting on this object monitor

void notifyAll()

Wakes up all threads that are waiting on this object's monitor.
Wake up all threads waiting on this object monitor

void wait( )

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll( ) method for this object.
Causes the current thread to wait until another thread calls this object notify( ) Method or notifyAll( ) method

life cycle

1. When a thread calls wait() or join, the thread will enter the waiting state. When notify or notifyAll is called, or after the execution of the join thread is completed, the thread will enter the runnable state

2. When the thread calls sleep(time) or wait(time), it enters the timed waiting state,

Finally, leave a question to think about. Why should wait be defined in Object instead of Thread?

To explain, let's recall that in the synchronous code block, we said that we need an object lock to achieve the mutual exclusion effect of multithreading, that is, the Java lock is object level, not thread level.

Why must wait be written in a synchronized code block?

The reason is to prevent the CPU from switching to other threads, and other threads execute the notify method in advance, which can not meet our expectations (wait first and then wake up by other threads), so we need a synchronization lock to protect it

What are the thread pools provided by JDK? How should we use the actual development?
1. JDK represents the thread pool through the interface ExecutorService, and creates a variety of thread pool objects through the tool class Executors

2. The characteristics of various thread pools are as follows:

newSingleThreadExecutor Create a singleton thread pool, which will only use a unique worker thread to execute tasks, ensuring that all tasks are in the specified order(FIFO, LIFO, priority)Execution.
newFixedThreadPool Create a fixed length thread pool to control the maximum concurrent number of threads. The exceeded threads will wait in the queue.
newCachedThreadPool Create a cacheable thread pool. If the length of the thread pool exceeds the processing needs, you can flexibly recycle idle threads. If there is no recyclable thread, you can create a new thread.
newScheduledThreadPool Create a fixed length routing pool to support regular and periodic task execution.

3. How do we use it in actual development? (key points)

In actual development, thread resources must be provided through thread pool, and it is not allowed to create threads explicitly in the application

The advantage of using thread pool is to reduce the time spent on creating and destroying threads and the overhead of system resources, and solve the problem of insufficient resources.
If the thread pool is not used, it may cause the system to create a large number of similar threads, resulting in memory consumption or "excessive switching"

In actual development, thread pools are not allowed to be created using Executors, but through ThreadPoolExecutor

FixedThreadPool and SingleThreadPool,The allowed request queue length is Integer.MAX_VALUE,A large number of requests may accumulate, resulting in OOM. 
CachedThreadPool and ScheduledThreadPool,The number of creation threads allowed is Integer.MAX_VALUE,A large number of threads may be created, resulting in OOM

Therefore, to sum up, we will all use the underlying method to create thread pools. You can see from the source code of various thread pools that they are created by the same class

Keywords: Java

Added by crob611 on Tue, 08 Feb 2022 13:07:26 +0200