线程和进程是什么?
线程是操作系统能够进行运算调度的最小单位,他被包含在进程之中。
进程是计算机系统进行资源分配和调度的基本单位,一个进程中可以有多个线程。
线程的状态分为几个过程
1.新建(NEW):新创建了一个线程对象。
2.可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
3.运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
4.阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。
5. 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
阻塞又分为哪几种
阻塞的情况分三种:
(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
3.线程阻塞方法
线程有2种阻塞方法,分别为wait()、sleep(),唤醒的方法为notify()和notifyAll(),interrupt()。
wait():使线程处于一种等待状态,释放所持有的对象锁。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用它时要捕获InterruptedException异常,不释放对象锁。
notify():唤醒一个正在等待状态的线程。注意调用此方法时,并不能确切知道唤醒的是哪一个等待状态的线程,是由JVM来决定唤醒哪个线程,不是由线程优先级决定的。
notifyAll():唤醒所有等待状态的线程,注意并不是给所有唤醒线程一个对象锁,而是让它们竞争。
interrupt():用于打断正在睡眠的线程。
sleep()和wait()有什么区别?
- sleep()方法是Thread的静态方法,wait则是Object的方法。任何对象的实例都能调用。
- sleep()方法调用的时候不会释放锁,也不会占用锁,wait()会释放锁,但调用他的前提是必须被synchronized所包围
- 他们都可以被interrupt()所打断
创建线程的方法有那些
- 继承Thread重写run()方法,
- 实现Runnable接口重写run()方法
- 实现callable接口
实现Runnable接口相比继承Thread类有如下优势:
- 可以避免由于Java的单继承特性而带来的局限;
- 增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的;
- 适合多个相同程序代码的线程区处理同一资源的情况。
实现Runnable接口和实现Callable接口的区别:
- Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
- Callable规定的方法是call(),Runnable规定的方法是run()
- Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void)
- call方法可以抛出异常,run方法不可以
- 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
- 加入线程池运行,Runnable使用ExecutorService的execute方法,Callable使用submit方法。
Lock和synchronized的选择
① Lock是一个接口, 而synchronized是Java中的关键字,synchronized是内置的语言实现;
② synchronized在发生异常时, 会自动释放线程占有的锁,因此 不会导致死锁现象发生; 而Lock在发生异常时,如果没有主动通过 unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
③ Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;(I/O和Synchronized都能相应中断,即不需要处理interruptionException异常)
④ 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
⑥ Lock可以提高多个线程进行读操作的效率。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。