线程的状态、实现与启动、实现同步的方法

1. 线程的状态
  1. public enum State {   
  2.     NEW,   
  3.     RUNNABLE,   
  4.     BLOCKED,   
  5.     WAITING,   
  6.     TIMED_WAITING,   
  7.     TERMINATED;   

(1)NEW(新建状态:A thread that has not yet started is in this state.):实例化Thread对象,但没有调用start()方法时的状态,isAlive()的放回结果为false。

(2)RUNNABLE(可运行状态:A thread executing in the Java virtual machine is in this state.):调用start()方法后的状态。处于RUNNABLE状态的线程在JVM上是运行着的,但是它可能还正在等待OS分配给它时间片才能运行,isAlive()的放回结果为true。

(3)BLOCKED(阻塞状态:A thread that is blocked waiting for a monitor lock is in this state.):线程正在等待其它的线程释放同步锁,以进入一个同步块或者同步方法继续运行;或者它已经进入了某个同步块或同步方法,在运行的过程中它调用了wait()方法,正在等待重新返回这个同步块或同步方法。

(4)WAITING(等待状态:A thread that is waiting indefinitely for another thread to perform a particular action is in this state.):当前线程调用了java.lang.Object.wait()、java.lang.Thread.join()或者java.util.concurrent.locks.LockSupport.park()三个中的任意一个方法,正在等待另外一个线程执行某个操作。比如一个线程调用了某个对象的wait()方法,正在等待其它线程调用这个对象的notify()或者notifyAll()方法来唤醒它;或者一个线程调用了另一个线程的join()方法,正在等待这个方法运行结束。

(5)TIMED_WAITING(定时等待状态:A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.):当前线程调用了java.lang.Object.wait(long timeout)、java.lang.Thread.join(long millis)、java.util.concurrent.locks.LockSupport.packNanos(long nanos)、java.util.concurrent.locks.LockSupport.packUntil(long deadline)四个方法中的任意一个,进入等待状态,但是与WAITING状态不同的是,它有一个最大等待时间,即使等待的条件仍然没有满足,只要到了这个时间它就会自动醒来。

(6)TERMINATED(死亡状态:A thread that has exited is in this state.):run()方法运行结束或被未catch的InterruptedException等异常终结,那么该线程完成其历史使命,它的栈结构将解散,也就是死亡了。但是它仍然是一个Thread对象,我们仍可以引用它,就像其他对象一样!它也不会被垃圾回收器回收了,因为对该对象的引用仍然存在。如此说来,即使run()方法运行结束线程也没有死啊!事实是,一旦线程死去,它就永远不能重新启动了,也就是说,不能再用start()方法让它运行起来!如果强来的话会抛出IllegalThreadStateException异常。如:
t.start();
t.start();

放弃吧,人工呼吸或者心脏起搏器都无济于事……线程也属于一次性用品。

注意(1):A thread can be in only one state at a given point in time. These states are virtual machine states which do not reflect any operating system thread states.

注意(2):sleep并不是Thread的一个状态

2. 线程的启动与实现

继承java.lang.Thread类或java.lang.Runnable接口,并重写它的run()方法,将线程的执行主体放入其中。这两种实现方式的区别并不大,继承Thread的类就不能再继承别的类了,因此也就不能继承别的类的有用的方法了;而使用Runnable接口的方式就不存在这个问题了,而且这种实现方式将线程主体和线程对象本身分离开来,逻辑上也较为清晰,所以推荐大家更多地采用这种方式。

要启动一个线程,必须调用Thread类的start()方法,而不是直接调用run()方法。启动线程的原理:首先都是调用start()方法启动一个线程,其次是在这个线程里执行目标对象target的run()方法。那么这个目标对象target是什么呢?为了弄明白这个问题,我们来看看Thread类的run()方法的实现:看源代码。

  1. public interface Runnable {
  2.     public abstract void run();
  3. }
  4. package java.lang;
  5. public class Thread implements Runnable {
  6.     //其他代码片段
  7.     private Runnable target;
  8.     public void run() {
  9.         if (target != null) {
  10.             target.run();
  11.         }
  12.     }
  13.     //其他代码片段
  14. }

当我们采用继承Thread实现线程时,线程的这个run()方法被重写了,所以当线程启动时,执行的是这个对象自身的run()方法;当我们采用继承Runnable实现线程时,构造器new Thread(Runnable target)将继承自Runnable的类的实例设置成为目标对象target,所以线程启动时,这个实例的run()方法就被执行了,这种方式可以把一个target赋给多个线程,这意味着几个线程将操作同一个对象、运行完全相同的作业。

总结起来就一句话,如果我们采用的是继承Thread类的方式,那么这个target就是线程对象自身;如果我们采用的是实现Runnable接口的方式,那么这个target就是实现了Runnable接口的类的实例。

3. 实现同步的方式:同步方法和同步块

给一个方法增加synchronized修饰符之后就可以使它成为同步方法,这个方法可以是静态方法和非静态方法,但是不能是抽象类的抽象方法,也不能是接口中的接口方法。同步方法具有排它性。当任意一个线程进入到一个对象的任意一个同步方法时,这个对象的所有同步方法都被锁定了,在此期间,其他任何线程都不能访问这个对象的任意一个同步方法,直到这个线程执行完它所调用的同步方法并从中退出,从而导致它释放了该对象的同步锁之后(仔细推敲,这句话并不准确:只有当synchronized 锁定的monitor是同一个时,方法才会被同步。eg:一个非static的synchronized,锁的时this,而static的synchronized锁的是Class,这两个方法在多线程中因为synchronized锁的monitor不一样,是可以被同时调用的)。在一个对象被某个线程锁定之后,其他线程是可以访问这个对象的所有非同步方法的;静态同步方法只受它所属类的其它静态同步方法的制约,而跟这个类的实例(对象)没有关系。

同步块是通过锁定某个指定对象,来对块中包含的代码进行同步。同步块锁定两个部分:(1)锁定指定对象,(2)锁定块中代码。同步块的对象并没有什么特别要求,任意一个对象都可以。如果一个对象既有同步方法,又有同步块,那么当其中任意一个同步方法或者同步块被某个线程执行时,这个对象就被锁定了,其他线程无法在此时访问这个对象的同步方法,也不能执行同步块。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值