极力推荐文章:欢迎收藏
和您一起终身学习,这里是程序员Android
1.什么是线程
线程就是进程中运行的多个子任务,是操作系统调用的最小单元
2.线程的状态
1.New:
新建状态,new
出来,还没有调用start
2.Runnable:
可运行状态,调用start
进入可运行状态,可能运行也可能没有运行,取决于操作系统的调度
3.Blocked:
阻塞状态,被锁阻塞,暂时不活动,阻塞状态是线程阻塞在进入
4.synchronized:
关键字修饰的方法或代码块(获取锁)时的状态。
5.Waiting:
等待状态,不活动,不运行任何代码,等待线程调度器调度,wait
、sleep
用来暂停当前线程的执行,以毫秒为单位,任何其它线程都可以中断当前线程的睡眠,这种情况下将抛出InterruptedException
异常
6.Timed Waiting:
超时等待,在指定时间自行返回
7.Terminated:
终止状态,包括正常终止和异常终止
3.线程的创建
线程创建的常用方法
1.继承Thread重写run方法
2.实现Runnable重写run方法
3.实现Callable重写call方法
实现Callable重写call方法
实现Callable
和实现Runnable类似,但是功能更强大,具体表现在
a.可以在任务结束后提供一个返回值,
Runnable
不行b.
call
方法可以抛出异常,Runnable
的run
方法不行c.可以通过运行
Callable
得到的Fulture
对象监听目标线程调用call
方法的结果,得到返回值,(fulture.get()
,调用后会阻塞,直到获取到返回值)
4.线程中断
一般情况下,线程不执行完任务不会退出,但是在有些场景下,我们需要手动控制线程中断结束任务,Java
中有提供线程中断机制相关的Api
,每个线程都一个状态位用于标识当前线程对象是否是中断状态
public boolean isInterrupted() //判断中断标识位是否是true,不会改变标识位
public void interrupt() //将中断标识位设置为true
public static boolean interrupted() //判断当前线程是否被中断,并且该方法调用结束的时候会清空中断标识位
需要注意的是interrupt()
方法并不会真的中断线程,它只是将中断标识位设置为true
,具体是否要中断由程序来判断,如下,只要线程中断标识位为false
,也就是没有中断就一直执行线程方法
new Thread(new Runnable(){
while(!Thread.currentThread().isInterrupted()){
//执行线程方法
}
}).start();
前边我们提到了线程的六种状态,New 、Runnable、 Blocked、 Waiting、 Timed Waiting、 Terminated
,那么在这六种状态下调用线程中断的代码会怎样呢,New
和Terminated
状态下,线程不会理会线程中断的请求,既不会设置标记位,在Runnable
和Blocked
状态下调用interrupt
会将标志位设置位true
,在Waiting
和Timed Waiting
状态下会发生InterruptedException
异常,针对这个异常我们如何处理?
1.在
catch
语句中通过interrupt
设置中断状态,因为发生中断异常时,中断标志位会被复位,我们需要重新将中断标志位设置为true
,这样外界可以通过这个状态判断是否需要中断线程
try{
....
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
2.更好的做法是,不捕获异常,直接抛出给调用者处理,这样更灵活
5.Thread为什么不能用stop方法停止线程
从SUN
的官方文档可以得知,调用Thread.stop()
方法是不安全的,这是因为当调用Thread.stop()
方法时,会发生下面两件事:
1.即刻抛出
ThreadDeath
异常,在线程的run()
方法内,任何一点都有可能抛出ThreadDeath Error
,包括在catch
或finally
语句中。2.释放该线程所持有的所有的锁。调用
thread.stop()
后导致了该线程所持有的所有锁的突然释放,那么被保护数据就有可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。
6.同步方法和同步代码块
为何要使用同步?java
允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查), 将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性和准确性。