线程的几种状态变化

进程是分配内存的单位,线程是CPU执行的基本单位


1.新建状态

使用new关键字和某线程类的构造方法创建线程对象,则该线程对象处于新建状态,表示系统已经为该线程对象分配了内存空间。处于新建状态的线程可以通过start()方法使他进入就绪状态。


2.就绪状态

该状态的线程已经具有了运行条件,进入线程队列,等待系统为他分配CPU资源,一旦获得CPU资源,该线程就进入运行状态。


3运行状态.

进入运行状态的线程执行自己run()方法中的代码。若遇到下列情况,将终止run()方法的执行

(1)调用当前线程的stop方法或destory方法使线程进入死亡状态

(2)调用当前线程的join或者wait方法进入阻塞状态,在规定时间内可以由其他线程调用notify()或notifyall()方法将其唤醒,使之进入就绪状态

(3)调用sleep()方法使线程进入阻塞状态,在睡眠时间过后再次进入就绪状态

(4)现在已弃用,suspend挂起线程,调用resume使其再次进入就绪状态。

(5)通过调用yield方法方法放弃线程的执行,并使之进入就绪状态。

(6)当线程要求I/O操作时,则进入阻塞状态

(7)若分配给当前线程的CPU时间片用完,则当前线程进入就绪状态。


4.阻塞状态

一个正在执行的线程如果执行suspend(有死锁风险)、join或sleep方法,或等待I/O设备的使用权,那么该线程将让出CPU的控制权并暂停中止自己的执行,进入阻塞状态。阻塞是他不能进入就绪队列,只有当阻塞的原因被消除时,线程在可以进入就绪状态,重新进入线程队列排队等待CPU资源,以便从原来终止处继续运行。

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

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

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


5.死亡状态

如果一个线程完成了全部工作或者被强制提前强制性的终止,则该线程处于死亡状态。

如果,每个Java程序都有一个默认主线程。对于应用,主线程是main()方法执行的线程。要实现多线程,必须在主线程中中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程。


注意:初看起来wait() 和 notify() 方法与suspend()和 resume() 方法对没有什么分别,但是事实上它们是截然不同的。区别的核心在于,前面叙述的suspend()及其它所有方法在线程阻塞时都不会释放占用的锁(如果占用了的话),而wait() 和 notify() 这一对方法则相反


上述的核心区别导致了一系列的细节上的区别

首先,前面叙述的所有方法都隶属于 Thread类,但是wait() 和 notify() 方法这一对却直接隶属于 Object 类,也就是说,所有对象都拥有这一对方法。初看起来这十分不可思议,但是实际上却是很自然的,因为这一对方法阻塞时要释放占用的锁,而锁是任何对象都具有的,调用任意对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放。而调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。


wait() 和 notify() 方法这一对方法必须在 synchronized 方法或块中调用,理由也很简单,只有在synchronized方法或块中当前线程才占有锁,才有锁可以释放。同样的道理,调用这一对方法的对象上的锁必须为当前线程所拥有,这样才有锁可以释放。因此,这一对方法调用必须放置在这样的 synchronized方法或块中,该方法或块的上锁对象就是调用这一对方法的对象。若不满足这一条件,则程序虽然仍能编译,但在运行时会出现IllegalMonitorStateException异常。


wait()  notify()方法的上述特性决定了它们经常和synchronized方法或块一起使用,将它们和操作系统的进程间通信机制作一个比较就会发现它们的相似性:synchronized方法或块提供了类似于操作系统原语的功能,它们的执行不会受到多线程机制的干扰,而这一对方法则相当于blockwake up 原语(这一对方法均声明为 synchronized)。它们的结合使得我们可以实现操作系统上一系列精妙的进程间通信的算法(如信号量算法),并用于解决各种复杂的线程间通信问题。


关于 wait() 和 notify() 方法最后再说明两点:

第一:调用notify() 方法导致解除阻塞的线程是从因调用该对象的 wait()方法而阻塞的线程中随机选取的,我们无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。

第二:除了notify(),还有一个方法 notifyAll()也可起到类似作用,唯一的区别在于,调用 notifyAll()方法将把因调用该对象的 wait()方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。

谈到阻塞,就不能不谈一谈死锁,略一分析就能发现,suspend()方法和不指定超时期限的wait()方法的调用都可能产生死锁。遗憾的是,Java并不在语言级别上支持死锁的避免,我们在编程中必须小心地避免死锁。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值