Java面试问题——线程全面详解总结

一、多线程是什么?为什么要用多线程?

介绍多线程之前要介绍线程,介绍线程则离不开进程。

首先进程 :是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元;

线程:就是进程中的一个独立控制单元,线程在控制着进程的执行。一个进程中至少有一个进程。

多线程:一个进程中不只有一个线程。

为什么要用多线程:

  • 为了更好的利用cpu的资源,如果只有一个线程,则第二个任务必须等到第一个任务结束后才能进行,如果使用多线程则在主线程执行任务的同时可以执行其他任务,而不需要等待;
  • 进程之间不能共享数据,线程可以;
  • 系统创建进程需要为该进程重新分配系统资源,创建线程代价比较小;
  • Java语言内置了多线程功能支持,简化了java多线程编程。

二、线程的生命周期:

新建 :从新建一个线程对象到程序start() 这个线程之间的状态,都是新建状态;

就绪 :线程对象调用start()方法后,就处于就绪状态,等到JVM里的线程调度器的调度;

运行 :就绪状态下的线程在获取CPU资源后就可以执行run(),此时的线程便处于运行状态,运行状态的线程可变为就绪、阻塞及死亡三种状态。

等待/阻塞/睡眠 :在一个线程执行了sleep(睡眠)、suspend(挂起)等方法后会失去所占有的资源,从而进入阻塞状态,在睡眠结束后可重新进入就绪状态。

终止 :run()方法完成后或发生其他终止条件时就会切换到终止状态。

三、创建线程的方法(还有其他方法):

1、继承Thread类:

步骤: 、定义类继承Thread;

  • 复写Thread类中的run方法;

目的:将自定义代码存储在run方法,让线程运行

  • 调用线程的start方法:

该方法有两步:启动线程,调用run方法。

2、实现Runnable接口:接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run 的无参方法。

实现步骤: 、定义类实现Runnable接口

  • 覆盖Runnable接口中的run方法
    将线程要运行的代码放在该run方法中。
  • 通过Thread类建立线程对象。
  • 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
    自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程执行指定对象的run方法就要先明确run方法所属对象
  • 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

3、通过Callable和Future创建线程:

实现步骤:

  • 创建Callable接口的实现类,并实现call()方法,改方法将作为线程执行体,且具有返回值。
  • 创建Callable实现类的实例,使用FutrueTask类进行包装Callable对象,FutureTask对象封装了Callable对象的call()方法的返回值
  • 使用FutureTask对象作为Thread对象启动新线程。
  • 调用FutureTask对象的get()方法获取子线程执行结束后的返回值。

四、继承Thread类和实现Runnable接口、实现Callable接口的区别。

继承Thread:线程代码存放在Thread子类run方法中。

  • 优势:编写简单,可直接用this.getname()获取当前线程,不必使用Thread.currentThread()方法。
  • 劣势:已经继承了Thread类,无法再继承其他类。

实现Runnable:线程代码存放在接口的子类的run方法中。

  • 优势:避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
  • 劣势:比较复杂、访问线程必须使用Thread.currentThread()方法、无返回值。

实现Callable:

  • 优势:有返回值、避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
  • 劣势:比较复杂、访问线程必须使用Thread.currentThread()方法建议使用实现接口的方式创建多线程。

五、线程状态管理

1、线程睡眠---sleep:

线程睡眠的原因:线程执行的太快,或需要强制执行到下一个线程。

线程睡眠的方法(两个):sleep(long millis)在指定的毫秒数内让正在执行的线程休眠。

sleep(long millis,int nanos)在指定的毫秒数加指定的纳秒数内让正在执行的线程休眠。

线程睡眠的代码演示:

1public class SynTest { 2 public static void main(String[] args) { 3 new Thread(new CountDown(),"倒计时").start(); 4 } 5} 6class CountDown implements Runnable{ 7 int time = 10; 8 public void run() { 9 while (true) { 10 if(time>=0){ 11 System.out.println(Thread.currentThread().getName() + ":" + time--); 12 try { 13 Thread.sleep(1000); 14 //睡眠时间为1秒 15 } 16 catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 } 20 } 21 } 22}

每隔一秒则会打印一次,打印结果为:

1倒计时:10 2倒计时:9 3倒计时:8 4倒计时:7 5倒计时:6 6倒计时:5 7倒计时:4 8倒计时:3 9倒计时:2 10倒计时:1 11倒计时:0

扩展:

Java线程调度是Java多线程的核心,只有良好的调度,才能充分发挥系统的性能,提高程序的执行效率。但是不管程序员怎么编写调度,只能最大限度的影响线程执行的次序,而不能做到精准控制。因为使用sleep方法之后,线程是进入阻塞状态的,只有当睡眠的时间结束,才会重新进入到就绪状态,而就绪状态进入到运行状态,是由系统控制的,我们不可能精准的去干涉它,所以如果调用Thread.sleep(1000)使得线程睡眠1秒,可能结果会大于1秒。

总结

同步的前提:

  1. 必须要有两个或者两个以上的线程。
  2. 必须是多个线程使用同一个锁。
  3. 必须保证同步中只能有一个线程在运行。
  4. 只能同步方法,不能同步变量和类。
  5. 不必同步类中所有方法,类可以拥有同步和非同步的方法。
  6. 如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法。
  7. 线程睡眠时,它所持的任何锁都不会释放。
    • 好处:解决了多线程的安全问题。
    • 弊端:多个线程需要判断,消耗资源,降低效率。

如何找问题?

  1. 明确哪些代码是多线程运行代码。
  2. 明确共享数据。
  3. 明确多线程运行代码中哪些语句是操作共享数据的。

写在最后

 

  • 第一:看完点赞,感谢您对作者的认可;
  • ...
  • 第二:随手转发,分享知识,让更多人学习到;
  • ...
  • 第三:记得点关注,每天更新的!!!
  • ...
点赞
收藏

评论区

加载中...

相关推荐

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Python基础10——线程、进程、协程

18线程18.1进程和线程进程:打开一个程序至少就会有一个进程。操作系统进行资源分配的基本单位线程:线程是CPU调度的基本单位,每个进程至少都有一个线程。单线程:只有一个线程pythondeffuna():print(123)deffunb():print(456)funa()funb()先执行funa再执行funb多线程线程

java多线程大汇总,线程与进程,线程调度,并发与并行,创建线程方式,线程生命周期,线程安全,线程通信,线程池

1.线程与进程进程是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间线程1、是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行.一个进程最少有一个线程2、线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程

java多线程的3种实现方式

多线程相关的问题1.什么是进程?​正在执行的程序2.什么是线程?​进程的子单位,一个能够完成独立功能的执行路径3.为什么需要开启多线程?当执行某些耗时操作的任务的时候需要开启多线程,防止线程阻塞能够让两个任务看起来像是在同时执行

python多线程原理和详解(一)

python多线程原理和详解线程概念1.线程是什么?线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。

4、jstack查看线程栈信息

1、介绍利用jps、top、jstack命令找到进程中耗时最大的线程,以及线程状态等等,同时最后还可以显示出死锁的线程查找:FoundoneJavaleveldeadlock即可1、jps获得进程号!(https://oscimg.oschina.net/oscnet/da00a309fa6

Java面试问题——线程全面详解总结 - HelloWorld