一、线程的创建
1.1 Thread的常见构造方法
方法 | 说明 |
Thread() | 创建线程对象 |
Thread(Runnable target) | 使用Runnable对象创建线程对象 |
Thread(String name) | 创建线程对象,并命名 |
Thread(Runnable target,String name) | 使用Runnable对象创建线程对象,并命名 |
1.2 继承Thread的方式创建线程
public class MyThread extends Thread{
@Override
public void run() {
System.out.println("t");
}
public static void main(String[] args) {
MyThread t=new MyThread();
t.start();//启动线程
System.out.println("main");//主线程的打印
}
}
MyThread
类继承了Thread
类,并重写了run()
方法。创建MyThread
的实例并通过调用start()
方法来启动新线程。
1.2 通过实现Runnable接口创建线程
创建一个实现 Runnable
接口的新类,并实现 run()
方法。然后,将这个类的实例传递给 Thread
类的构造函数。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("这里是线程运行的代码");
}
public static void main(String[] args) {
Thread t=new Thread(new MyRunnable());
t.start();
System.out.println("main");
}
}
1.3 使用匿名内部类创建线程
创建一个匿名内部类,同时继承 Thread
类或实现 Runnable
接口,并在创建时定义线程任务。
//使用匿名内部类实现继承thread
public class ThreadDemo3 {
public static void main(String[] args) {
Thread t=new Thread(){
@Override
public void run(){
while (true){
System.out.println("t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t.start();
while (true){
System.out.println("main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
另外一种实现runable接口的方式去实现线程的创建
//匿名内部类实现ThreadRunable接口
public class ThreadDemo4 {
public static void main(String[] args) {
Thread t=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
while (true){
System.out.println("main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
1.4 使用lambda 表达式创建 Runnable 子类对象
public class ThreadDemo5 {
public static void main(String[] args) {
Thread t=new Thread(() ->{
while (true){
System.out.println("t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
while (true) {
System.out.println("main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
使用lambda表达式是为了使代码看起来更加简洁,跟其他创建线程方法功能一样,除此之外,工作中使用的最多的也是这种
1.5 start方法和run方法的区别
run() 方法 只是线程的一个普通方法,调用它不会创建一个新的线程,而只是按顺序执行其中的代码。因此,如果直接调用 run() 方法,那么其中的代码会在当前线程中执行,不会开启新的线程。
start() 方法 才是真正启动一个新线程并开始执行其中的 run() 方法。当调用 start() 方法时,Java 会创建一个新的线程,并在新的线程中执行 run() 方法中的代码。因此,如果要启动一个新线程并执行其中的代码,就必须使用 start() 方法。
当主线程main调用t.start()方法的时候,另外一个线程就已经启动,开始执行run方法.代表另一个线程线程已经开始,但同时主线程也在启动.进而产生并发.
二.线程中断
线程中断是指在多线程程序中,中断正在运行的线程的执行,通常是由其他线程通过调用目标线程的interrupt()方法来实现。被中断的线程可以捕获这个中断信号并做出相应的处理。
2.1 interrupt()方法
interrupt()
方法是一种请求中断线程的机制。它不会立即停止线程的执行,而是设置线程的中断状态,使线程能够根据这个状态来决定自己的行为。interrupt()
方法是 Thread
类的一个实例方法,可以被任何其他线程调用,用来请求中断目标线程。
1. 设置中断状态:当 interrupt() 方法被调用时,它会将目标线程的中断状态设置为 true。
2. 线程检查中断状态:线程需要定期检查自己的中断状态。这通常在执行关键操作之后或者在循环的检查点进行。
3. 响应中断:线程可以选择响应中断状态,执行必要的清理工作,并安全地退出。线程也可以选择忽略中断状态,继续执行。
class InterruptibleTask implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
// 执行任务
Thread.sleep(1000); // 休眠1秒
System.out.println("执行任务");
} catch (InterruptedException e) {
// 处理中断
System.out.println("程序已经被中断了");
// 清理资源
return; // 退出run方法
}
}
}
}
public class test {
public static void main(String[] args) {
Thread taskThread = new Thread(new InterruptibleTask());
taskThread.start();
// 让任务线程运行一段时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 请求中断任务线程
taskThread.interrupt();
System.out.println("请求中断");
}
}
InterruptibleTask
在一个循环中执行任务,并在每次迭代后检查是否被中断。当主线程调用 taskThread.interrupt()
时,任务线程会捕获 InterruptedException
并安全地退出。
2.2 interrupted()方法
interrupted() 是 Java 中 Thread 类的一个静态方法,它用于检查当前线程的中断状态,并且与 isInterrupted() 方法不同,interrupted() 在检查后会清除中断状态。这个方法通常用于流式操作中,以便在处理中断时能够保持中断状态的一致性。
检查中断状态:interrupted() 方法检查当前线程的中断状态。
清除中断状态:无论中断状态如何,interrupted() 方法都会将中断状态重置为未中断(false)。
返回中断状态:该方法返回当前线程的中断状态。
public class Demo {
private static class MyRunnable implements Runnable {
@Override
public void run() {
// 两种方法均可以
while (!Thread.interrupted()) {
//while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName()
+ ": 别管我,我忙着转账呢!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName()
+ ": 有内鬼,终止交易!");
// 注意此处的 break
break;
}
}
System.out.println(Thread.currentThread().getName()
+ ": 啊!险些误了大事");
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target = new MyRunnable();
Thread thread = new Thread(target, "李四");
System.out.println(Thread.currentThread().getName()
+ ": 让李四开始转账。");
thread.start();
Thread.sleep(10 * 1000);
System.out.println(Thread.currentThread().getName()
+ ": 老板来电话了,得赶紧通知李四对方是个骗子!");
thread.interrupt();
}
}
3.isInterrupted()方法
在Java中,isInterrupted()方法是用来检查线程的中断状态,但不会清除线程的中断状态。这个方法是一个实例方法,可以通过Thread类的实例来调用。
查询中断状态:isInterrupted() 方法检查调用它的线程的中断状态。
返回中断状态:该方法返回一个布尔值,表示线程的中断状态。如果线程被中断过,或者中断状态被设置过,它将返回 true。
中断状态不清除:调用 isInterrupted() 方法后,线程的中断状态保持不变。
package threrading;
public class Demo9 {
public static void main(String[] args) {
Thread t = new Thread(()->{
while (!Thread.currentThread().isInterrupted()){
System.out.println("hello t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
});
t.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.interrupt();
}
}
三、线程等待
有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。例如,张三只有等李四转 账成功,才决定是否存钱,这时我们可以使用join方法明确等待线程的结束。
方法 | 说明 |
public void join() | 等待线程结束 |
public void join(long millis) | 等待线程结束,最多等 millis 毫秒 |
public void join(long millis, int nanos) | 同理,但可以更高精度 |
阻塞等待:当线程A调用线程B的join()方法时,线程A会暂停执行,直到线程B的run()方法执行完毕。
释放锁:在join()方法调用期间,线程A会释放它持有的任何同步锁,这允许其他线程在这些锁上操作。
继续执行:一旦线程B完成执行,线程A会解除阻塞,并继续执行join()方法之后的代码。
public class Demo {
public static void main(String[] args) throws InterruptedException {
Runnable target = () -> {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName()
+ ": 我还在工作!");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ": 我结束了!");
};
Thread thread1 = new Thread(target, "李四");
Thread thread2 = new Thread(target, "王五");
System.out.println("先让李四开始工作");
thread1.start();
thread1.join();
System.out.println("李四工作结束了,让王五开始工作");
thread2.start();
thread2.join();
System.out.println("王五工作结束了");
}
}
四、线程休眠
线程休眠是通过 Thread 类中的 sleep() 方法实现的。当一个线程调用 sleep() 方法时,它会进入休眠状态,暂停执行一段时间,然后重新开始执行。
方法 | 说明 |
public static void sleep(long millis) throws InterruptedException | 休眠当前线程 millis 毫秒 |
public static void sleep(long millis, int nanos) throws InterruptedException | 可以更高精度的休眠 |
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println(System.currentTimeMillis());
Thread.sleep(3 * 1000);//让此线程休眠3秒
System.out.println(System.currentTimeMillis());
}
}
五、获取当前线程引用
获取线程的实例非常的简单,就是调用Thread.currentThread()方法,因为线程的调度是不可控的,所以,这个方法只能保证实 际休眠时间是大于等于参数设置的休眠时间的。
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
System.out.println(thread.getName());
}
}