1、什么是线程?什么是进程?以及他们之间的关系
进程:是指一段程序的运行过程,是资源分配的基本单位,
线程:是CPU独立运行和调度的基本单位,程序执行的最小单位
*两者之间的联系:都是操作系统程序运行的基本单元
*两者的区别:
(1)地址空间:进程之间的地址空间独立,线程共享本进程的地址空间
(2)资源拥有:进城之间资源独立,线程之间共享所属进程的资源,如:内存,CPU,IO等(线程有自己的堆和栈)
(3)执行过程:每个进程都有一个程序执行入口;线程是不能独立执行的,必须依存在进程,由程序的多线程机制控制
(4)健壮性:一个进程奔溃不会影响其他进程的执行,一个线程奔溃会导致进程的奔溃
(5)通信:进程间通信CPI,线程间可以直接读写进程数据段(共享空间)进行通信,但是需要线程的同步和互斥手段,以保证数据一致性
(6)调度和切换:线程上下文切换比进程上下文切换要快很多
2、实现线程的方式?(两种)实现线程的两种方式使用哪一种更好?
(1)继承Thread;(2)实现Runnable接口
实现Runnable接口更好,原因:
(1)java只能是单继承
(2)一个类继承Tread不适合资源共享,相反实现Runnable接口很容易实现资源共享
(适合多个相同的程序代码的线程去处理同一个资源 )
(3)线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
不管是扩展Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的
3、线程的状态有哪几类,以及状态的转换?
(1)创建:新建一个线程
(2)就绪:指调用了线程的start()方法,该状态的线程位于可运行线程池,等待获取CPU的使用权
(3)运行:就绪的线程获取了CPU,开始执行
(4)阻塞:线程因为某些原因放弃了CPU,暂时停止工作,只有再次进入就绪状态才有机会转入运行态,阻塞的三种情况:
①等待阻塞:运行的线程执行了wait()方法,JVM将其放入到等待池
②同步阻塞:运行的线程在获取锁的时候,被其他线程抢占,JVM会将其放入锁池
③其他阻塞:运行的线程执行了sleep()方法或join()方法,或者发出了I/O请求,JVM会把该线程置为阻塞态,这些线程执行结束后,线程会重新转入就绪态
(5)死亡:线程执行结束或因异常退出了run()方法,该线程结束生命周期
4、start()和run()的区别?
Start()是启动一个线程(不是立即执行,而是使线程变为可运行态),run()是执行当前线程的方法。调用start()才能实现多线程
5、“不可变”对象?
“可变”是指变量的值在其生命周期内是可以发生改变的
我们知道不可变的对象一定是线程安全的,并且永远也不需要额外的同步(因为一个不可变的对象只要构建正确,其外部可见状态永远都不会发生改变)。所以“可变”意味着存在线程不安全的风险。
6、Java中Semaphore是什么?
Semaphore信号量,是一个计数信号量:通常用于限制可以访问某些资源的数目
临界区:是对多线程的串行化来访问公共资源,在任意时刻只允许一个线程对共享资源进行访问,只有临界区被释放后,其他线程才可以被被抢占
互斥量:用互斥对象机制,只有拥有互斥对象的线程才可以访问公共资源,互斥不仅能实现同一应用程序的公共资源安全,还能实现不同应用程序的公共资源安全共享(互斥锁:Synchronized)
信号量:允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目
事件:通过通知操作的方式来保持线程的同步,还可以方便实现多个线程的优先级比较的操作
信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在 哪里)。而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这 个资源
7、解释一下什么是死锁?死锁产生的原因?死锁产生的条件?
死锁是指两个线程A,B争夺同一资源s,线程A开始执行,线程A需要用到线程B执行完后的结果,这时线程A因需等待B的结果而进入阻塞状态,线程B开始运行,但却无法获取资源s,线程B也进入阻塞状态,此时两个线程处于相持状态,即死锁
8、线程的性质:原子性、可见性、有序性
9、线程调度:调整线程的优先级(默认为5,范围1~10),线程的优先级具有继承关系
10、函数
sleep():线程睡眠,使线程从运行态到阻塞态,睡眠结束后转为就绪态
yield():退让,暂停当前正在执行的线程对象,把执行机会让给相同或者更高的优先级
目的:是让有相同优先级的线程之间能适当的轮转执行,让线程从运行态转至可运行态
Join():线程加入,在当前线程中调用另一个线程的jion方法,则当前线程进入阻塞状态,直至另一个进程运行结束
Wait():线程进入等待,直到其他线程调用此对象的notify()或notifyAll()方法唤醒,等价于wait(0)
Obj.wait(),obj.notify(),必须与synchronized(obj)一起使用,即wait(),notify()只针对已经获取obj锁的进行操作,即wait()是在线程获取对象锁后主动释放对象锁,同时本线程休眠,直到其他线程调用对象的notify()唤醒线程,notify()调用后并不是立马释放锁,而是在synchronized语句块之行结束,自动释放锁。
Notify():线程唤醒,还有notifyAll()该操作唤醒所有线程
Interrupt():中断某个线程,某个资源还未来得及关闭,即run方法还未执行结束,就强行结束线程,会导致资源无法关闭。可以用来中断某个线程,给线程发送一个中断信号,让线程在无限等待时(如死锁)能够抛出异常,从而结束线程;如果你将异常解决,那么就不会中断
*Sleep()和yield()的区别?
执行sleep()的线程时间未到是不能恢复执行态的,时间确定,较低优先级的线程有机会执行
而yield()有可能从可执行态又马上被执行,时间不定,只让给高优先级线程执行
*sleep()和wait()的区别?
Sleep()是将当前线程阻塞,暂停程序,让出CPU,但不释放锁,无法执行同步方法,指定时间到了若无比它优先级高的线程执行就会恢复运行态,否则需等待
Wait()是让线程进入等待状态,线程会释放锁,其他线程可以调用其同步方法,只有调用notify()方法后本线程才能进入锁定池准备