线程有几种状态,产生的条件

  1. 新建状态(New) :线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。

  2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的 start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU 调度执行。

  3. 运行状态(Running):线程获取CPU 权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。

  4. 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃 CPU 使用权,暂时停止运行。直到线程进 入就绪状态,才有机会转到运行状态。

    阻塞的情况分三种:

    ⚫ 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。

    ⚫ 同步阻塞 -- 线程在获取 synchronized 同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。

    ⚫ 其他阻塞 -- 通过调用线程的 sleep()或 join()或发出了 I/O 请求时,线程会进入到阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入就绪状态。

  5. 死亡状态(Dead):线程执行完了或者因异常退出了 run()方法,该线程结束生命周期

产生死锁的基本条件

  • 产生死锁的原因

    (1) 因为系统资源不足。

    (2) 进程运行推进的顺序不合适。

    (3) 资源分配不当等。

如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。

  • 产生死锁的四个必要条件

    (1) 互斥条件:一个资源每次只能被一个进程使用。

    (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

    (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

    (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

  • 死锁的解除与预防

理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源。因此,对资源的分配要给予合理的规划。

线程池

线程池就是事先将多个线程对象放到一个容器中,当使用的时候就不用 new 线程而是直接去池中拿线程即可,节省了开辟子线程的时间,提高的代码执行效率。

在 JDK 的 java.util.concurrent.Executors 中提供了生成多种线程池的静态方法。

ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); 

ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(4); 

ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(4); 

ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();

调用他们的 execute 方法即可。

优点如下

  1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

  2. 提高响应速度。当 任务到达时,任务可以不需要等到线程创建就能立即执行。

  3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

Java 自带几种线程池

  1. newCachedThreadPool

    创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。这种类型的线程池特点是: 工作线程的创建数量几乎没有限制(其实也有限制的,数目为 Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。

    如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为 1 分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。 在使用 CachedThreadPool 时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。

  2. newFixedThreadPool

    创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池 初始的最大数,则将提交的任务存入到池队列中。FixedThreadPool 是一个典型且优秀的线程池,它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是,在线程池空闲时,即线程池中没有可运行任 务时,它不会释放工作线程,还会占用一定的系统资源。

  3. newSingleThreadExecutor

    创建一个单线程化的 Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它, 保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。

  4. newScheduleThreadPool

    创建一个定长的线程池,而且支持定时的以及周期性的任务执行。例如延迟 3 秒执行。

文章作者: 已删除用户
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yida
Mark Interview
喜欢就支持一下吧