目录
10. interrupt() 停止一个线程——return返回
CPU执行的代码:就是说这个线程要做什么,就是代码。
代码操作的数据:
虚拟处理机:不是说多线程是并行运行的吗?那么多个线程同时运行,就需要有多个处理机去处理,而CPU只有一个,那么就通过软件来模拟出过个虚拟的处理机。
main()方法是程序的入口,那么调用main()方法是线程是由JVM创建的线程,名字叫main。
1、继承Thread类
public class BBB extends Thread{
@Override
public void run(){
System.out.println("hellooooo");
}
}
public class Test{
public static void main(String[] args){
BBB b = new BBB();
b.start();
}
}
BBB类继承了Thread类,重写了run()方法,run()方法中的代码就是此线程要执行的代码,但是要通过start()方法来触发run()方法的执行,也就是说必须要调用start()方法才能让线程执行起来。
2. 实现Runnable接口
public class BBB implements Runnable{
@Override
public void run(){
System.out.println("hellooooo");
}
}
public class Test{
public static void main(String[] args){
BBB b = new BBB();
Thread t = new Thread(b);
t.start();
}
}
通过实现Runnable接口的方式来实现线程。
3. currentThread() 方法
Thread.currentThread() 方法是获取调用当前代码段的线程,举个例子:
public class Test {
public static void main(String[] args) {
ThreadOne threadOne = new ThreadOne();
threadOne.run();
}
}
public class ThreadOne extends Thread{
public ThreadOne(){
System.out.println("构造方法:" + Thread.currentThread().getName());
}
@Override
public void run() {
System.out.println("run方法:" + Thread.currentThread().getName());
}
}
运行结果:
分析: new ThreadOne()创建线程对象的时候,是main线程调用的,所以打印出来的也是main。 第二个run()方法也是main线程调用的,所以打印的也是main。
注意:threadOne.run() 和 threadOne.start() 是有区别的,run()单纯是调用run方法,而start()是启动一个线程,然后线程去执行run方法。
我们改一下:
public class Test {
public static void main(String[] args) {
ThreadOne threadOne = new ThreadOne();
threadOne.start();
}
}
public class ThreadOne extends Thread{
public ThreadOne(){
System.out.println("构造方法:" + Thread.currentThread().getName());
}
@Override
public void run() {
System.out.println("run方法:" + Thread.currentThread().getName());
}
}
运行结果:
此时的第二个打印出来的就是Thread-0。这个名字是线程默认的线程名初始化规则生成的。因为start()方法是启动了线程,然后线程执行的run方法,所以当然是新线程的线程名咯。
4. isAlive() 方法
判断一个线程是否还“存活”,存活状态是指线程启动了,但是还没有终止的这段时间。
5. sleep() 方法
让当前线程休眠多少毫秒。那么当前线程到底是什么线程呢? 就是currentThread() 返回的线程。
6. getId() 方法
每一个线程不仅有线程名,还有一个唯一的标志ID, getId() 方法就是获取当前线程的唯一ID号。
7. 停止线程
stop() 方法可以停止一个线程,但是不安全,已被淘汰。 大多数线程停止操作通过 interrupt() 方法,它不能终止一个正在运行的线程,需要一些参数判断才能。
interrupt() 方法。 详细说一下,这个方法只是改变一个线程的中断标志,仅此而已,线程的中断标志(true 或 false),true表示中断状态,false表示未中断状态,调用interrupt() 方法就是将中断标志设置为true,当一下线程正在正常运行的时候,是不会去检查这个中断标志的,只有当阻塞的时候,才会频繁去检查这个中断标志,wait()、join()、sleep() 方法都会使线程进入阻塞,如果阻塞期间,该线程调用了interrupt() 方法,那么检查到中断标志已经变为了true,此时出错了,因为本来我线程只是阻塞了,还没有终止呢,但是此时检查到线程已经处于中断状态,就要抛出异常,那么java虚拟机会将中断标志改为false,等抛出了异常,这个线程就算退出了。
interrupted() 方法,线程的这个方法是用于判断“当前线程”是否已经中断,实际就是检查“中断标志”,将中断标志返回。注意:这个方法调用一次后,会清理掉中断标志,比如,当前线程调用了interrupt() 方法,中断标志是true,此时又调用interrupted() 方法,返回值为true,但是接着又调用interrupted() 方法,这个方法返回值就是 false,因为第一个调用完了之后,就清理掉中断标志了(中断标志变为false)。
isInterrupted() 方法。调用这个方法的线程对象(就是线程)是否已经处于中断状态,返回也是true 或 false, 但是isInterrupted() 方法不会清理中断标志。
8. interrupt() 停止一个线程——抛出异常法
举例说明:
public class Test {
public static void main(String[] args) throws InterruptedException {
InterruptOne interruptOne = new InterruptOne();
Thread thread = new Thread(interruptOne);
thread.start(); 启动线程
Thread.currentThread().sleep(2); main线程停止2毫秒,就是不要马上执行interrupt方法,要等interruptOne执行2毫秒的时候,在interrupt
thread.interrupt();
}
}
public class InterruptOne extends Thread {
@Override
public void run() {
super.run();
for(int i = 0; i <= 1000; i ++){
if(Thread.interrupted()){
System.out.println("线程终止!");
break;
}
System.out.println("i = " + i);
}
System.out.println("依然继续运行着,至此才结束");
}
}
运行结果:
分析:说明interrupt() 方法只是改变了线程的中断标志,而并不会影响线程的继续运行(除了阻塞)。
用抛出异常的方法让线程终止
public class Test {
public static void main(String[] args) throws InterruptedException {
InterruptException interruptException = new InterruptException();
Thread thread = new Thread(interruptException);
thread.start();
Thread.currentThread().sleep(4);
thread.interrupt();
}
}
public class InterruptException extends Thread {
@Override
public void run() {
super.run();
try {
for(int i = 0; i <= 1000; i ++){
if(Thread.interrupted()){
System.out.println("线程终止!");
throw new InterruptedException();
}
System.out.println("i = " + i);
}
System.out.println("依然继续运行着,至此才结束");
}catch (Exception e){
System.out.println("抛出异常导致线程终止");
}
}
}
运行结果:
分析:这次是直接throw new InterruptException() 抛出异常的方法,直接终止线程的剩余部分执行。
9. interrupt() 停止一个线程——阻塞中停止
阻塞包括wait()、sleep()、join()方法,此处就以sleep() 为例。
public class Test {
public static void main(String[] args) throws InterruptedException {
InterruptSleep interruptSleep = new InterruptSleep();
Thread thread = new Thread(interruptSleep);
thread.start();
Thread.sleep(100); main线程睡眠100毫秒,目的是让interruptSleep线程要跑起来,并且进入睡眠阻塞状态
thread.interrupt();
}
}
public class InterruptSleep extends Thread {
@Override
public void run() {
super.run();
try {
System.out.println("开始了");
Thread.sleep(1000);
System.out.println("结束了");
}catch (Exception e){
System.out.println("线程在睡眠中就抛出了异常");
}
}
}
运行结果:
分析:因为在interruptSleep线程睡眠期间,它的中断标志变为了true,就会抛出异常,所以结果如上。
10. interrupt() 停止一个线程——return返回
public class Test {
public static void main(String[] args) throws InterruptedException {
InterruptOne interruptOne = new InterruptOne();
Thread thread = new Thread(interruptOne);
thread.start(); 启动线程
Thread.currentThread().sleep(2); main线程停止2毫秒,就是不要马上执行interrupt方法,要等interruptOne执行2毫秒的时候,在interrupt
thread.interrupt();
}
}
public class InterruptOne extends Thread {
@Override
public void run() {
super.run();
for(int i = 0; i <= 1000; i ++){
if(Thread.interrupted()){
System.out.println("线程终止!");
return;
}
System.out.println("i = " + i);
}
System.out.println("依然继续运行着,至此才结束");
}
}
在线程的run方法中,直接使用return,也可以达到立即终止线程的效果。
11. 挂起线程和唤醒线程——suspend、resume
这两个方法已经是过期方法,因为方法存在不安全。
占用公共资源(死锁、阻塞)。这是因为suspend() 方法会使一个线程处于挂起状态,什么都不执行,但是却没有结束终止,试想,有公共资源的情况下,多个线程都要访问这个公共资源,此时A线程访问到了,但是A线程挂起了,那么其它线程就无法再访问这个资源了,只要A线程还处于挂起状态(不释放资源的锁),那么其它要访问资源的线程都要阻塞在那,什么也做不了。
数据不同步。线程也许改变了部分数据,突然挂起,那么剩余部分数据仍未改变,此时的数据是不一致的,如果此时有其它线程使用这些数据的话,就会导致不正确的结果。
12. yield() 方法
这个方法是让线程放弃cpu资源,但是放弃多久呢?不确定,只是让线程放弃当前占用的cpu资源,也许放弃了之后,立马又是此线程占用cpu。
13. 守护线程
线程分为两种:守护线程、非守护线程(用户线程)。
守护线程就是一旦启动,就会一直运行到最后彻底结束了,它才结束。比如:java的垃圾收集器,只要java程序运行着,那么垃圾收集器就一直运行着,当所有java程序都运行完了,垃圾收集器才运行结束。
如果系统中还有非守护线程在运行,那么守护线程就不能终止,除非所有的非守护线程就运行结束了,没有其它非守护线程在运行了,那么此时守护线程才终止结束。
设置方法: 线程对象.setDaemon( true );