多线程

线程池的状态

 

 

 

线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated

Running:(1) 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。 
      (2) 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!

ShutDown:(1) 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。 
      (2) 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。

Stop:(1) 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。 

   (2) 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。

 Tidying:
  (1) 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线           程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。 
      (2) 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。 
                          当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

TERMINATED:(1) 状态说明:线程池彻底终止,就变成TERMINATED状态。 

        (2) 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。

线程的启动和创建

线程在操作系统的真正创建是调用了start方法后,才会进行创建;

new Thread();进行了初始化,当调用start()方法,会调用本地方法start0(),进行jvm 的线程创建,通过jvm 的线程创建,进而创建操作系统的线程创建。

 

sleep和wait的区别

1、这两个方法来自不同的类分别是Thread和Object。 

2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。 

3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在。

 

wait和notify配合syncronized一起使用的原因

如果 wait 和 notify/notifyAll 不强制和 synchronized 一起使用,那么在多线程执行时,就会出现 wait 执行了一半,然后又执行了添加数据和 notify 的操作,从而导致线程一直休眠的缺陷。

class MyBlockingQueue {
    // 用来保存数据的集合
    Queue<String> queue = new LinkedList<>();
 
    /**
     * 添加方法
     */
    public void put(String data) {
        // 队列加入数据
        queue.add(data); 
        // 唤醒线程继续执行(这里的线程指的是执行 take 方法的线程)
        notify(); //
    }
 
    /**
     * 获取方法(阻塞式执行)
     * 如果队列里面有数据则返回数据,如果没有数据就阻塞等待数据
     * @return
     */
    public String take() throws InterruptedException {
        // 使用 while 判断是否有数据(这里使用 while 而非 if 是为了防止虚假唤醒)
        while (queue.isEmpty()) { //// 没有任务,先阻塞等待
            wait(); //
        }
        return queue.remove(); // 返回数据
    }
}

我们在代码中标识了三个关键执行步骤:①:判断队列中是否有数据;②:执行 wait 休眠操作;③:给队列中添加数据并唤醒阻塞线程。如果不强制要求添加 synchronized,那么就会出现如下问题:

步骤线程1线程2
1 执行步骤 ① 判断当前队列中没有数据  
2   执行步骤 ③ 将数据添加到队列,并唤醒线程1继续执行
3 执行步骤 ② 线程 1 进入休眠状态  

如果 wait 和 notify 不强制要求加锁,那么在线程 1 执行完判断之后,尚未执行休眠之前,此时另一个线程添加数据到队列中。然而这时线程 1 已经执行过判断了,所以就会直接进入休眠状态,从而导致队列中的那条数据永久性不能被读取,这就是程序并发运行时“执行结果混乱”的问题。

 

wait和notify为啥用while不用if

https://www.cnblogs.com/ibcdwx/p/13733874.html

如果是if,它不会进行二次判断;所以wait使用要在while内,while会一直判断是否符合条件。

nofiyAll()方法调用时,不知道哪条线程不该被唤醒,所以需要再次进行判断。

 

posted @ 2022-05-31 19:25  腾龙皓月  阅读(23)  评论(0)    收藏  举报