Maybe 发表于 2024-6-20 11:49:09

JAVA面试之多线程和特点分析

本帖最后由 Maybe 于 2024-6-20 12:02 编辑

1.什么是进程
进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。

2.什么是线程
线程:进程内部的一个独立执行单元;一个进程可以同时并发的运行多个线程,可以理解为一个进程便相当于一个单 CPU 操作系统,而线程便是这个系统中运行的多个任务。

3.并发和并行:
①并发:指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上有多个进程同时执行的效果
②并行:指在同一时刻,有多条指令在多个处理器上同时执行。

4.多线程有什么优势?
答:①进程之间不能共享内存,但线程之间共享内存非常容易
②系统创建进程时需要为该进程重新分配系统资源,但创建线程则代价小得多,因此使用多线程来实现多任务并发比多进程的效率高
③Java语言内置了多线程功能支持,从而简化了Java的多线程编程

5.Thread和Runnable的区别
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

6.多线程的生命周期
答:在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)五种状态。
流程:
1)、新建状态(New):新创建了一个线程对象。
2)、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3)、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4)、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)
5)、死亡状态(Dead):线程会以一下三种方式结束:
①run()或call()方法执行完成,线程正常结束
②线程抛出一个未捕获的Exception或Error
③直接调用该线程的stop()方法来结束线程——该方法容易导致死锁
注:当主线程结束时,其他线程不受影响,不会随之结束。
线程睡眠:Thread.sleep(long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。
   线程等待:Object类中的wait()方法(无限等待),导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait(0) 一样。
   线程让步:Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。
   线程加入:join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
   线程唤醒:Object类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。 直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。类似的方法还有一个notifyAll(),唤醒在此对象监视器上等待的所有线程。

7.什么是线程安全和线程不安全?
答案:由于系统的线程调度具有一定的随机性,当使用多个线程来访问同一个数据时,很容易“偶然“出现线程安全问题。
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

8.线程安全问题
(1)什么叫线程安全
答: 就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问,直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。
(2)何为线程不安全
答:线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

9.线程同步锁有什么特点
答:同步代码块:synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
synchronized(obj){需要同步的代码(多条语句操作共享数据的代码)}
obj:同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.
1. 锁对象可以是任意类型。
2. 多个线程对象要使用同一把锁。

10.同步有什么特点:
答:同步的前提是:多个线程并且多个线程使用的是同一个锁对象

11.同步的有什么好处
答:同步的出现解决了多线程的安全问题

12.同步有什么弊端
答:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

13.同步方法:
答:同步方法就是使用synchronized关键字来修饰某个方法,则该方法称为同步方法。同步方法的同步监视器是this,也就是调用该方法的对象。

14.同步锁是谁?
答:对于非static方法,同步锁就是this。
对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。

15.线程安全的类具有什么特征
答:①该类的对象可以被多个线程安全的访问
②每个线程调用该对象的任意方法之后都将得到正确结果
③每个线程调用该对象的任意方法之后,该对象状态依然保持合理状态。

16. Java 中 sleep 方法和 wait 方法的区别?(答案)
答:虽然两者都是用来暂停当前运行的线程,但是 sleep() 实际上只是短暂停顿,因为它不会释放锁,而 wait() 意味着条件等待,这就是为什么该方法要释放锁,因为只有这样,其他等待的线程才能在满足条件时获取到该锁

17.run()方法和start()方法区别:
答:run()方法是多线程程序的一个约定。所有的多线程代码都在run方法里面。启动线程使用start()方法,不是run()方法。调用start()方法来启动线程,系统会把该线程run()方法当成线程执行体来处理。如果直接调用run()方法,则run()方法会被当成普通方法立即执行,而不是线程执行体。而且在run()方法返回之前其他线程无法并发执行。

18.多线程有几种实现方法?同步有几种实现方法?
答:①多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
②同步的实现方面有两种,分别是synchronized,wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉
InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某
一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

19.启动一个线程是用run()还是start()?
答:启动一个线程是调用start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法是该线程所关联的执行代码。

20.当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
答:分几种情况
1).其他方法前是否加了synchronized关键字,如果没加,则能。
2).如果这个方法内部调用了wait,则可以进入其他synchronized方法。
3).如果其他个方法都加了synchronized关键字,并且内部没有调用wait,则不能。
4).如果其他方法是static,它用的同步锁是当前类的字节码,与非静态的方法不能同步,因为非静态的方法用的是this。

21.线程的基本概念、线程的基本状态以及状态之间的关系
答:①一个程序中可以有多条执行线索同时执行,一个线程就是程序中的一条执行线索,每个线程上都关联有要执行的代码,即可以有多段程序代码同时运行,每个程序至少都有一个线程,即main方法执行的那个线程。(如果只是一个cpu,它怎么能够同时执行多段程序呢?这是从宏观上来看的,cpu一会执行a线索,一会执行b线索,切换时间很快,给人的感觉是a,b在同时执行,好比大家在同一个办公室上网,只有一条链接到外部网线,其实,这条网线一会为a传数据,一会为b传数据,由于切换时间很短暂,所以,大家感觉都在同时上网。)
②线程基本状态:就绪,运行,synchronize阻塞,wait和sleep挂起,结束。wait必须在synchronized内部调用。调用线程的start方法后线程进入就绪状态,线程调度系统将就绪状态的线程转为运行状态,遇到synchronized语句时,由运行状态转为阻塞,当synchronized获得锁后,由阻塞转为运行,在这种情况可以调用wait方法转为挂起状态,当线程关联的代码执行完后,线程变为结束状态。

22.简述synchronized和java.util.concurrent.locks.Lock的异同 ?
答:主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。

页: [1]
查看完整版本: JAVA面试之多线程和特点分析