Java basic thread study notes

1. What is a thread?

After a program runs, it is a process. A thread is created by a process and is an entity of the process. A process can have multiple threads, but a thread belongs to only one process.

2. Three ways to create threads

1. Implement the Runnable interface

Directly implement the Runnable interface, and then need to rewrite its run() method (this run() method is a method in the Runnable interface, and we need to write business logic in it ourselves) Use
cases:

public class ThreadDemo {
    
    
    public static void main(String[] args){
    
    
        Dog dog = new Dog();
        Thread thread = new Thread(dog);//需要把实现了Runable接口的对象当作参数,因为.start方法是Thread的方法,Runable接口并不存在
        thread.start();         //通过start()启动一个线程
    }
}
class Dog implements Runnable{
    
    
    @Override
    public void run() {
    
    
        System.out.println("==这个方法里写我们自己的业务逻辑==");
    }
}

Points to note

  • Only by calling .start() will a thread be started, otherwise the thread is just created and not executed
  • The reference variable that implements the Runable interface needs to be used as a parameter, because the .start method is a Thread method, and there is no such method in the Runable interface
  • The run() method is a method to be called back after the thread is started (direct call will not start the thread)

2. Inherit the Thread class

The Thread class is a class that implements the Runnable interface.
Use cases:

public class ThreadDemo{
    
    
    public static void main(String[] args){
    
    
        Cat cat = new Cat();//创建线程
        cat.start();		//启动线程
    }
}
class Cat extends Thread{
    
    	//继承Thread类
    @Override
    public void run() {
    
    
        System.out.println("==这里写我们的逻辑==");
    }
}

The difference between inheriting the Thread class and implementing the Runnable interface

  1. From the perspective of java design, there is essentially no difference in creating threads by inheriting Thread or implementing the Runnable interface . The Thread class itself implements the Runnable interface.
  2. Implementing the Runnable interface is more suitable for the situation where multiple threads share a resource , and avoids the limitation of single inheritance
    . For example:
public class ThreadDemo{
    
    
    public static void main(String[] args){
    
    
        Cat cat = new Cat();
        new Thread(cat).start;
        new Thread(cat).start;
        new Thread(cat).start;
        System.out.println("三个线程在卖同一只猫咪");
    }
}
class Cat extends Demo implements Runnable{
    
    	//如果是继承Thread类的话就没办法再继承其他类了,而且每次new出来的都是不同的Cat
    @Override
    public void run() {
    
    
  			while(true){
    
    
  			      System.out.println("==出售猫咪==");
			}
    }
}

3. Implement the callable interface

Can be divided into several steps to achieve.

  1. Implement the Callable interface (this interface is generic and needs to define the data type, which is also the return type of the thread)
  2. Rewriting the call method requires a generic return value, and can also throw an exception.
  3. Create a thread pool (only possible through thread pool)
  4. Submit to execute this thread class
  5. get return value
  6. Close the thread pool service

Code example:

public class CallableDemo implements Callable<String>{
    
    	// 1. 实现Callable接口
    @Override
    public String call() throws Exception {
    
    	 			//2. 重写call方法,需要一个泛型的返回值,也可以抛出一个异常。
        return "第三种方式创建线程";
    }
}
//使用线程池,运行Callable接口实现类中的方法call,获取返回值
class ThreadPool{
    
    
    public static void main(String[] args) throws Exception {
    
    
        //创建线程池 (静态工厂方法 ,Executors是一个工厂  )
        ExecutorService es = Executors.newFixedThreadPool(2);	// 3.创建线程池(只能通过线程池实现)
        //运行线程 (submit方法需要一个 Future<V>的返回值)
        Future<String> submit = es.submit(new CallableDemo()); // 4.提交执行这个线程类
        //获取返回值的内容
        String s = submit.get();			// 5.获取返回值
        System.out.println(s);
        es.shutdown();						// 6. 关闭线程池服务
    }
}

The difference between implementing the Runnable interface and implementing the Callable interface

  1. To implement the Runnable interface, you need to rewrite the run() method. This method cannot have a return value. To implement the Callable interface, you need to rewrite the call() method. This method can have a return value and can throw an exception
  2. Implementing the Callable interface only supports the use of thread pools and does not support the use of thread classes
  3. Implement the Callable interface to obtain the return value after the thread pool is executed

3. Lambda expression

Threads can be started using Lambda expressions .

4. Static proxy mode

5. Why use .start to start the thread instead of calling the run method directly?

Because if you directly call the run method of the thread class, it is still executed in the main thread (main thread) by default, and does not restart a thread. It will execute the ordinary run method and then execute the following program, only the .start method Only then will a thread be started and the callback function of the run() method executed.

6. Thread execution

  • After we start a java program, it will enable the main main thread, and other created sub-threads are run in this main thread, and the main thread and sub-threads are executed alternately. After the content of the main thread is executed, the main thread will die, and the sub-threads will continue to execute. The program will stop only when all threads are dead.
  • All threads are actually executed alternately and not at the same time, depending on the scheduling of the cpu.

7. Thread common methods

  • start ---- start the thread
  • setName ---- set the thread name
  • getName ---- returns the name of the thread
  • setPriority ---- change the priority of the thread
  • getPriority ---- get the priority of the thread
  • sleep ---- Make the currently executing thread sleep (pause execution) for the specified number of milliseconds
  • interrupt ---- interrupts the thread but does not really end the thread. So it is generally used to interrupt the sleeping thread
  • yield ---- the politeness of the thread (not necessarily successful)
  • join ---- Thread queue jumping (must be successful)
  • getStatus ---- get the status of the current thread
  • wait ---- thread waiting - (method of Object class, can only be used in synchronous method or synchronous code block)
  • notify ---- wake up the waiting thread - (method of Object class, can only be used in synchronous method or synchronous code block)
  • notifyAll ---- wake up all waiting threads - (method of Object class, can only be used in synchronous method or synchronous code block)
    use cases:
public class ThreadDemo{
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        ThreadA threadA = new ThreadA();
        threadA.start();    //启动线程
        threadA.setName("线程A"); //设置该线程的名字为线程A
        System.out.println("该线程的名字为"+threadA.getName());
        System.out.println("该线程优先级="+threadA.getPriority());
        threadA.setPriority(1); //设置该线程的优先级为1(默认是5,可改为1-10,等级越高被cpu调度的概率越高)
        threadA.sleep(10000); //该线程休眠10秒(只能通过interrupt()来中断睡眠) (这个方法不会释放锁)
        threadA.interrupt(); //中断正在休眠的线程
        threadA.wait();     //线程等待,这个方法会释放锁,通过notify()或notifyall()来唤醒继续执行任务)
        System.out.println("ss");
        threadA.notify();   //唤醒该线程 (唤醒之后这个线程会继续去抢锁)
        threadA.notifyAll(); //唤醒所有等待线程
        threadA.yield();    //让出cpu,让其他线程执行,但礼让的时间不确定,所以也不一定礼让成功(cpu足够的话会一起执行)(thread01. yield() cpu不够时thread01线程会让让其他线程先执行)
        threadA.join();   //遇到线程threadA等它执行所有任务才会继续执行自己的任务
    }
}
class ThreadA extends Thread {
    
    
    @Override
    public void run() {
    
    
        System.out.println("==这是线程A==");
    }
}

8. Thread deadlock

Thread deadlock means that two or more threads are blocked infinitely, and the threads wait for each other for resources.
For example: thread A needs the resources of thread B, and thread B needs the resources of thread A. If they can't get them, they will all enter the blocked state.
Example:
Please add a picture description

The following two situations will cause thread deadlock

  • When two threads call Thread.join();
  • When two threads use nested synchronization blocks, one thread occupies the necessary lock of the other thread and is blocked while waiting for each other, a deadlock may occur.

How to avoid thread deadlock

  • Let the program acquire at most one lock at a time. Of course, in a multi-threaded environment, this is usually not realistic

  • Threads are locked in a certain order

  • When the thread tries to acquire the lock, add a certain time limit. If the time limit exceeds the time limit, it will give up the request for the lock and release the lock it owns (of course synchronized does not have this function, but we can use the tryLock method in the Lock class to try to acquire the lock. , this method can specify a timeout period, after waiting for the timeout period to return a failure message)

Nine.Synchronized keyword

For some code blocks or methods, we hope that only one thread can access them at the same time, so we need to modify them with the Synchronized keyword. It can also be understood as thread synchronization, that is, when a thread is operating on memory, other threads cannot operate on this memory address, until the thread completes the operation, other threads can operate on the memory address.

Synchronized role

  • Each object has a mutex identifier, and Synchronized is equivalent to locking the door. Only by obtaining this lock can the tasks inside be executed. The first one to reach this method gets the object lock, and other threads (threads that need to access this method at the same time) enter the blocked state (the program cannot continue to execute without the lock). As soon as the lock is released, the blocked threads will start to grab the lock at the same time (the thread that released the lock can also participate), and whoever grabs it will execute first.

Example: It is as if a friend closes the door (locks) before going to the toilet, and then comes out (unlocks) after finishing the work. Then other friends can use the toilet again.

The lock will be released in the following four situations

  • The execution of the synchronization method and synchronization code block of the current thread ends
  • The current thread encounters a break or return in a synchronous code block or synchronous method
  • The current thread has an unhandled Error or Exception in the synchronization code block or synchronization method, resulting in an abnormal end
  • The current thread executes the wait() method of the thread object in the synchronization code block and synchronization method, the current thread pauses, and releases the lock

Precautions

  • The lock of the non-static synchronization method: it can be this (the object currently created), or other objects (such as Object, but it must be the same object, such as selling tickets in the way of extends is not the same object.)
  • The lock of the static synchronization method: it is in the current class itself. (can work on all instances of this class)

Use Cases:

public class ThreadDemo{
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        ThreadA sellTicket = new ThreadA();
        new Thread(sellTicket).start();
        new Thread(sellTicket).start();
        new Thread(sellTicket).start();
    }
}
class ThreadA implements Runnable {
    
      //这里需要注意如果使用extends继承Thread类的话那他们访问的并不是同一个资源
    int ticketNum = 100;
    private boolean loop = true;           //控制循环方法运行状态
    Object xxx = new Object();
    public /*synchronized*/ void sell(){
    
         //1.加在同步方法上
        synchronized (this/*xxx*/){
    
                    //2.加在代码块上
            if (ticketNum<=0){
    
    
                System.out.println("售票结束....");
                loop = false;
                return;
            }
            try {
    
    
                Thread.sleep(50);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("窗口"+Thread.currentThread().getName()+
                    "售出一张票-->"+"剩余"+(--ticketNum)+"张票");
        }
    }
    //用于静态方法上的话,锁是加在ThreadA.class这个类上的
    public synchronized static void m1(){
    
       //静态同步方法
            System.out.println("m1");
    }
    public  static void m2(){
    
    
        synchronized (ThreadA.class){
    
           //静态同步方法块synchronized(当前类的class){ }
            System.out.println("m2");
        }
    }
    @Override
    public void run() {
    
    
        while (loop){
    
    
            sell();
        }
    }
}

If you don't add the synchronized keyword, and there is only one ticket left, three threads may enter the sell() method at the same time, and all perform -1 to ticketNum, and the ticket will be oversold.

use judgment

  • Locked code needs to be analyzed first
  • Select a synchronized code block or a synchronized method (usually using a synchronized code block, with a small scope)
  • The lock object of multiple threads is required to be the same (for example, the thread class instantiating the A extends Thread object is not the same object)
  • Using synchronized program execution efficiency will be lower

Ten.Lock lock

11. Daemon thread

A daemon thread is a thread that serves ordinary threads. When all threads end, the daemon thread will automatically end. The most common daemon thread is the garbage collection mechanism of java.

How to set a thread as a daemon thread

Call it before a thread starts!
Use Cases:

public class ThreadDemo{
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        MyDaemonThread myDaemonThread = new MyDaemonThread();
        myDaemonThread.setDaemon(true);//设置该线程为守护线程(一定要在.start()方法前设置)
        myDaemonThread.start();
        for (int i = 0; i < 10; i++) {
    
    
            System.out.println("宝强在辛苦的工作....");
            Thread.sleep(1000);
        }
    }
}
class MyDaemonThread extends Thread{
    
    
    @Override
    public void run() {
    
    
        while(true){
    
     //守护线程无限循环,主线程结束循环也会跟着结束
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("马蓉和宋喆快乐聊天,哈哈哈~~~");
        }
    }
}

12. Thread termination

There are three ways to end a thread:

  • When the thread completes the task, it will automatically exit.
  • Use the thread's stop() method (the stop method is outdated and dangerous, just like turning off the computer power suddenly, it is not recommended to use)
  • Stop the thread by using variables to control the way the run method exits, that is, the notification method (some threads are executed in a loop, you can use this method to jump out of the loop to end the thread), use cases:
public class ThreadDemo{
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        A a = new A();
        a.start();
        Thread.sleep(5000);   //让主线程休眠5秒
        a.setLoop(false);
    }
}
class A extends Thread {
    
    
    int count = 0;
    private boolean loop = true; //设置一个控制变量
    public void setLoop(boolean loop) {
    
    
        this.loop = loop;
    }
    @Override
    public void run() {
    
    
        while(loop){
    
    
            try {
    
    
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("A线程运行中==="+(++count));
        }
    }
}

Thirteen. The life cycle of the thread (six states of the thread)

  1. NEW (new state): A state in which a thread has just been created but has not yet started (new xxxTheard())
  2. Runnable (ready state): After the thread starts, it will enter the ready state. In this state, it can be divided into two states: ready and running. It is determined by the system scheduler, but the speed is too fast so it looks like it is running execute together
  3. Timed Waiting: Threads in the ready state will enter the timed waiting or waiting state after passing Thread.sleep(), t.wait(), t.join() and other methods, and will return to the ready state after the time is over
  4. Waiting (waiting): Threads in the ready state will enter the timeout waiting or waiting state after passing Thread.sleep(), t.wait(), t.join() and other methods, but to end this state, you need to use t.notify( ) or t.notifyAll() and other methods (return to the ready state)
  5. Blocked (blocked state): The thread in the ready state will enter the blocked state when it waits to enter the lock of the synchronization block code, and will return to the ready state after obtaining the lock (for example, when a thread encounters a method modified by synchronized, other threads do not lock in If you don't go, you will enter the blocked state)
  6. Terminated (terminated state): The thread that has died is in this state

The cycle diagram looks like this:

Please add a picture description

14. Thread pool

Resources that are frequently created and destroyed and use a large amount of resources, such as threads in concurrent situations, have a great impact on performance. So you can create multiple threads in advance, put them into the thread pool, get them directly when you use them, and put them back into the pool after use. It can avoid frequent creation and destruction and achieve reuse.
Benefits of using a thread pool:

  • Improved responsiveness (reduced time to create new threads)
  • Reduce resource consumption (reuse threads in the thread pool, do not need to create each time)
  • Facilitates thread management (....)

JDK 5.0 provides thread pool-related APIs: ExecutorService and Executors . Executors is a tool class and a thread pool factory class, which is used to create and return different types of thread pools. ExecutorService is the real thread pool interface . Commonly subclassed ThreadPoolExecutor.
ExecutorService has two methods for executing threads.

  • void execute(Runnable command): no return value, generally used to execute Runnable
  • Future submit(Callable task): There is a return value, and Callable is usually executed again (implementing the callable interface, there is above)

Execute the thread through excute:

public class RunnableThreadPool {
    
    
    public static void main(String[] args) {
    
    
        ExecutorService server = Executors.newFixedThreadPool(5);   //创建最大线程数为5的线程池
        //执行线程 (无返回值)
        server.execute(new myThread());
        server.execute(new myThread());
        server.execute(new myThread());
        server.execute(new myThread());
        //关闭连接
        server.shutdown();
    }
}
class myThread implements Runnable{
    
    
    @Override
    public void run() {
    
    
        System.out.println(Thread.currentThread().getName());
    }
}

video

Guess you like

Origin blog.csdn.net/cc1373709409/article/details/123130093
Recommended