创建线程的三种方式:
一、继承Thread类创建线程类
1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程需要完成的任务。
2)创建Thread子类的实例,即创建线程对象。
3)调用创建线程的start()方法启动该线程。
注:Thread.currentThread():currentThread()是Thread类的静态方法,该方法总是返回当前正在执行的线程对象。
二、实现Runnable接口创建线程类
1)定义Runnable接口的是实现类,并重写该接口的run方法。
2)创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真的线程对象。
SecondThread st = new SecondThread();
new Thread(st);
3)调用线程对象的start()方法。
三、 使用Callable和Future创建线程
1)创建Callable接口实现类,并实现call方法,该call方法作为线程执行体,且该call方法具有返回值。
2)创建Callable实现类的实例,使用FutureTask类来包装Callable 对象,该FutureTask对象封装了该Callable对象的call方法返回值。
3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
4)调用FutureTask对象的get方法来获得子线程执行结束后的返回值。
创建线程的三种方式对比
通过实现Runnable与Callable接口实现多线程基本相同,只是Callable接口里定义的方法具有返回值,可以声明抛出异常而已。
其与继承Thread类的方式主要有一下区别:
1)线程只是实现了Runnable与Callable接口,还可以实现其他的类。
2)在后者方式下,多个线程共享一个target对象,所以非常适合多个相同线程来处理同一份资源。
3)使用继承Thread类来获取线程对象直接使用this即可获得当前线程,而前者需要调用Thread.currentThread方法。
线程的生命周期
新建,就绪,运行,阻塞,死亡。
一、新建(NEW),就绪(Runnable)
当程序使用new关键字创建了一个线程后,该线程就处于新建状态,此时它和其他java对象一样,仅仅由java虚拟机分配内存,并初始化其成员变量的值。
当线程调用了start方法之后,该线程就处于就绪状态,java虚拟机会为其创建方法调用栈和程序计数器,处于这个状态的线程并没有开始运行,只是表示可以开始运行了,至于何时开始运行,取决于JVM里线程调度器的调度。
二、运行(RUNNING)阻塞(Blocked)
如果处于就绪状态的线程获得了cpu,开始执行run方法的执行体,则线程处于运行状态。
当一个线程运行后,它不可能一直处于运行状态,线程在运行过程中需要被中断,目的是使其他线程获得执行机会。
当发生如下情况,线程进入阻塞状态:
1)线程调用sleep()方法主动放弃所占用的处理器资源。
2)线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞。
3)线程试图获得一个同步监视器,但该同步监视器被其他线程所持有。
4)线程等待某个通知notify
5)程序调用了线程的suspend方法将该线程挂起(容易造成死锁)
当发生如下情况,线程由阻塞转为就绪
1)调用sleep方法经过了指定时间。
2)线程调用的阻塞式IO方法得到返回
3)线程成功获得所请求的同步监视器
4)线程正在等待某个通知时,其他线程发出了通知。
5)处于挂起状态的线程调用了resume恢复方法
三、线程死亡(DEAD)
线程会以如下三种方式结束,结束后就处于死亡状态。
1)run或call方法执行完成,线程正常结束。
2)线程抛出一个未捕获的Exception或Error。
3)直接调用该线程的stop方法来结束该线程(容易死锁)。
为了测试线程是否死亡,可以调用对象的isAlive方法,当线程处于就绪,运行,阻塞3种状态时,该方法返回true.。
控制线程
一、join线程
Thread提供了一个线程等待另一个线程完成的方法--join方法。当在某个线程中调用其他线程的join方法,调用线程会被阻塞,直到被join方法加入的join线程执行完为止。
二、守护线程
有一种线程,在后台运行,它的任务是为其他线程提供服务,这种线程称为后台线程(Daemon Thread),又称为精灵线程或守护线程。Jvm垃圾回收线程就是典型的后台线程。
后台线程的特征:如果所有的前台线程都死亡,后台线程会自动死亡。
调用Thread对象的setDaemon(true)方法(必须在start方法之前调用),可以将指定线程设置成后台线程。Thread还提供一个isDaemon方法,判断一个线程是否是后台线程。
三、线程让步yield
它是Thread类提供的一个静态方法,它也可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转化为就绪状态,yield只是让当前线程暂停一下,让系统的线程调度器重新调度一次。