JavaEE——Thread类的基本用法

多线程是Java中的常用操作,而要实现多线程,则需要借助于Thread类。

多线程的基本用法包括创建、终断、等待、休眠等。

线程的创建

创建一个新线程通常有两种方法:创建类并继承Thread、实现Runnable接口。

继承Thread类只需要重写run方法即可:

class myThread extends Thread {
    @Override
    public void run() {
        System.out.println("这是一个新线程");
    }
}

通过实例化对象并调用start方法启动新线程:

myThread t = new myThread();
t.start();

实现Runnable接口类似:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        //这里写新线程的执行操作
    }
}

这时启动新线程的操作有所不同:

MyRunnable runnable = new MyRunnable();
Thread t = new Thread(runnable);
t.start();

为了使代码更加简洁可以使用匿名内部类或者lambda表达式(这里介绍lambda的写法):

lambda表达式的写法为:(参数1, 参数2, …) -> {//这里写具体实现的语句},即:

Thread t = new Thread(() -> {//run方法参数为空,则只写一个()即可
    //这里写run方法要执行的操作
});

线程的休眠

线程的休眠是指让当前线程暂停执行一段时间,让出CPU的时间片,以便其他线程有机会执行。可以通过Thread.sleep休眠当前线程。但是,调用sleep可能出现受查异常,因此需要处理该异常:

Thread t = new Thread(() -> {
    while (true) {
        System.out.println("hello t");
        try {
            Thread.sleep(1000);//1000代表休眠1000ms,实际休眠时间是>=1000ms的
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
t.start();

线程的中断

线程的中断一般有两种:通过设置自定义标识符中断、调用interrupt方法。

设置自定义标识符

当我们设置一个普通的标识符时,如果使用匿名内部类或者lambda表达式会出现某些问题:

即匿名内部类中只能接收final或者说"实际 final"——即不变的量。

要解决这个问题可以考虑使用成员变量:

public class ThreadDemo {
    public static boolean flag = false;
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (!flag) {
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
    }
}

调用interrupt()方法

通过Thread.currentThread.isInterrupted()获得标志位(Thread.currentThread获取当前线程,也就是t线程),再通过interrupt更改标志位使其不满足循环条件:

Thread t = new Thread(() -> {
   while (!Thread.currentThread().isInterrupted()) {
       System.out.println("hello t");
       try {
           Thread.sleep(1000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
});
t.start();
try {
    Thread.sleep(3000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
t.interrupt();//设置标志位为true

不过这样并不能使程序停下:

这是由于sleep的缘故:

如果处于休眠态的线程被强行中断,则sleep会在抛出异常的同时清除中断状态。也就是说主线程中的t.interrupt()设置的一次标志中断休眠后又被清除了,这时就又满足循环条件。而主线程只设置了一次标志位,那么t线程就会继续不断地执行下去。

因此需要我们在打印异常信息后及时的break出去:

线程的等待

线程的等待是指线程在等待某个条件满足时进入休眠状态,等待被唤醒。

join方法可以使当前线程进入阻塞状态,即CPU停止调度当前线程,转而去调度其他的线程,等到其他的线程结束后再执行当前线程。例如:

Thread t = new Thread(() -> {
    for (int i = 0; i < 3; i++) {
        System.out.println("执行" + (i + 1) + "次");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
t.start();
//join方法中可以设置参数,参数为线程等待的最大时长
t.join();//只有t线程执行完毕,才能继续执行主线程
System.out.println("执行完毕!");

线程的等待除了通过join方法外,还可以通过加锁操作,即sychronized()方法(实际上是调用了Object.wait方法)等。

猜你喜欢

转载自blog.csdn.net/weixin_71020872/article/details/129638256