Java并发编程-学习笔记(三)

Java启动线程的方法

  • 继承Thread类,覆盖run方法,调用start方法启动
  • 实现Runnable接口,作为传参实例化一个Thread类,调用start方法启动

这个问题在百度的一面面试中还被问到了。


 

currentThread()

这是currentThread源码

 

native方法,实现就不管了,看注释:返回一个当前执行中线程对象的引用。这个执行中线程对象难道不是这个Thread实例吗?可这又是static方法,要怎么返回非static成员。

再看几段源码就明白了。

这是Thread类,它实现了Runnable接口

这是他的两个构造方法,在第一个问题中启动一个线程的第二种方法就是用一个实现了Runnable接口的类去初始化Thread类。

再来看run()方法的实现

 

这就说明我们其实是可以用一个重写了run()方法的Thread对象来初始化另一个Thread对象的。调用Thread的start()方法就会去调用它的run()方法,而run()方法调用的target.run()方法。

然后看下面两个例子。

输出

 

输出

 

简单来说,currentThread()返回的是调用start()方法的实例的引用,而调用了谁的run()方法,就看run()方法调用链的底端是谁。

如果我们再把代码改成这样

输出

在这里,MyThread类重写了run()方法,所以这里不是链式的调用,因为产生多态了。

扯了这么多,感觉有些废话。因为把Thread当传参初始化Thread的情况,一般也不会有吧。


 

isAlive()

该方法用来判断线程是否处于活动状态。

也要注意一个地方,看下面的例子吧

 

原因还是this和Thread.currentThread的区别。对于b来说,a只是实现了Runnable接口而已,提供了run()方法,但并不关心它是个什么类,父类是什么,有什么其他的成员函数。写成下面这样就很明白了,这貌似也是面向接口编程的体现。

 


暂停线程

在Java中有以下三种方法可以终止正在运行的线程

  1. 使用退出标记,使线程正常退出,也就是等run()方法执行结束后线程终止
  2. 使用stop()方法强行终止线程,不推荐,stop()和suspend()、resume()都是过期的方法。
  3. 使用interrupt()方法中断线程

interrupt()

interrupt()方法仅仅是在当前线程中打下一个停止的标记,并不是真正的停止线程。

Thread类中两个判断线程是否中断的方法

  • interrupted(): 测试当前线程是否被中断,指的是Thread.currentThread()
  • isInterrupted(): 测试该线程是否被中断,指的是this

看下源码吧,注释中解释的很清楚

 

两个方法中都用到了isInterrupted(boolen)这个方法,再来看他的源码和注释

 

测试线程有没有被中断,即有没有被调用interrupt()方法,而且,如果ClearInterrupted这个传参是true的话,中断状态会被重置。

测试下interrupted()方法吧,体会一下被重置

 

然后来比较一下这两个方法:

interrupted() isInterrupted() 备注
static方法 非static 表现出:前者与当前执行线程有关,后者只与当前类实例有关
调用currentThread().isInterrupted(boolean) this.isInterrupted(boolean) this和currThread的区别,前面讨论的很多了
清空中断状态 不清空中断状态 isInterrupted(boolean ClearInterrupted)的参数决定的

所以我觉得保险点的判断当前线程是否中断,但又不想重置状态,可以Thread.currentThread().isInterrupted()来判断。

这两个方法设计出来是用来中断线程的,上面扯的都是状态的获取和改变,要终止线程,可以结合interrupted()和return语句。另外可以考虑抛出异常,catch语句中可以继续向上抛,finally语句中可以用来做些收尾工作。

记忆方法:说了这么多如果记混了,可以参考下我的记忆方法。从Java方法命名的角度考虑,isInterrupted()方法是getter方法的命名方式,是获取类实例成员且不改变成员的方法,所以就认为它跟类实例有关。

stop()

非常暴力的中断线程的方法,已经不建议使用了,我认识到的两个原因

  • 导致一些收尾工作没有机会完成,如释放资源之类的
  • 直接释放锁,导致数据同步出错,出现数据不一致的情况

线程暂停

suspend() 和 resume()

暂停和恢复是通过Thread的suspend()和resume()两个方法,也不再建议使用了。

suspend()方法是不释放锁的,所以如果线程在运行同步方法或者同步代码块,会导致锁得不到释放,其他线程也无法获得锁。可是如果不是在运行同步方法,又会有数据不同步的危险,但我觉得这个不是suspend()方法的错,如果数据需要同步但又不加任何限制,即使不调用suspend(),也可能有其他同步问题。

当我们调用一些库函数的时候,我们可能也想不到它是同步方法,而无意使用suspend()了,例如:

 

yield()

yield() 放弃当前的CPU资源,将它让给其他任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃就又获得了CPU时间片。


线程优先级

  • Java的线程优先级分为1~10这10个等级
  • 线程优先级有继承的特性,A线程启动B线程,则B线程的优先级就和A线程是一样的
  • 高优先级的线程总是大部分先执行完,而不是高优先级的线程全部先执行完,具有随机性

发表评论

电子邮件地址不会被公开。 必填项已用*标注