线程问题

来源:互联网 发布:java xmn 编辑:程序博客网 时间:2024/06/05 12:41

并发问题

并发不一定得是多线程,多进程也可以实现并发。

java线程的实现、线程的高度、线程的状态切换

java提供线程的实现方式都是native的,因为不同的硬件和操作系统提供线程调度方式并不尽相同,所以java没用采用和平台无关的统一手段来实现。实现线程的主要3种方式:内核实现,用户线程实现、用户线程加轻量级进程混合实现

1)内核线程实现

内核线程(KLT)就是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换。

程序一般不会直接使用内核线程,而是去使用内核线程的一种高级接口—轻量级进程(LWP),轻量级进程就是我们所讲的线程,这种轻量级进程与内核线程之间1:1的对应关系。

优点:

内核直接支持,由操作系统内核创建和撤销。内核维护进程及线程的上下文信息以及线程切换。一个内核线程由于I/O操作而阻塞,不会影响其它线程的运行。

缺点:

1、线程的操作、创建、同步等都需要系统调用,而系统调用代价比较高,需要在用户态和内核态中来回切换。

2、每个轻量级的进程都需要一个内核线程来支持,需要消耗一定的内核资源。


2)用户线程实现

用户线程指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。

不需要用户态/核心态切换,速度快,操作系统内核不知道多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。

优点:

切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗。

缺点:

多核处理器很难讲线程映射到其他处理器上,单线程阻塞会造成该进程阻塞。


3)线程调度

线程调度主要是指系统为线程分配处理器使用权的过程,主要分为:协同式线程调度和抢占式线程调度(java)

抢占式线程调度

抢占式线程调度中每个线程由系统来分配执行时间,线程的切换不由线程本身来决定。

优点:

线程的执行时间系统可控,不会出现单个线程阻塞造成整个进程阻塞。

java就是采用抢占式线程调度,另外,java还可以通过给线程设置优先级来建议系统给某些线程多分配一点时间,不过不是很靠谱,线程的调度最终还是取决的操作系统。

4)状态转换

java定义了5中线程状态,任意一个时间点,一个线程有且只有其中一个状态。

①新建状态(new):创建了一个线程对象

②就绪状态(runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权。即在就绪状态的进程除CPU之外,其它的运行所需资源都已全部获得。

③运行状态:就绪状态的线程获取了CPU,执行程序代码。

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

线程阻塞的三种状态:

a) 等待阻塞运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()notifyAll()方法才能被唤醒。

b) 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中。

c) 其他阻塞:运行的线程执行sleep()join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态

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



实现线程的两种方式:继承Thread类和实现Runnable接口

当线程调用了自身的sleep()方法或其他线程的join()方法,进程让出CPU,然后就会进入阻塞状态(不释放锁)。sleep()结束或join()结束后,该线程进入可运行状态,继续等待OS分配CPU时间片。

线程调用了yield()方法,意思是放弃当前获得的CPU时间片,回到就绪状态,这时与其他进程处于同等竞争状态,OS有可能会接着又让这个进程进入运行状态; 调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间片从而需要转到另一个线程。yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。

当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同),进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()notifyAll()方法才能被唤醒。wait()  notify() 方法这一对方法却必须在 synchronized 方法或块中调用。










原创粉丝点击