属性 | 获取方法 |
---|---|
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
方法1: 继承 Thread 类
1)继承 Thread 来创建一个线程类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("这里是线程运行的代码");
}
}
2)创建 MyThread 类的实例
MyThread t = new MyThread();
3)调用 start 方法启动线程
t.start(); // 线程开始运行
方法2: 实现 Runnable 接口
1)实现 Runnable 接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("这里是线程运行的代码");
}
}
2)创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为 target 参数
Thread t = new Thread(new MyRunnable());
3)调用 start 方法
t.start(); // 线程开始运行
对比上面两种方法:
其他方法:
Thread t=new Thread(){
@Override
public void run(){
System.out.println("hello tread");
}
};
t.start();
Thread t=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
});
t.start();
Thread t=new Thread(()->{
System.out.println("hello");
});
t.start();
在上面我们已经看到了如何通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。
调用 start 方法, 才真的在操作系统的底层创建出一个线程。
李四一旦进到工作状态,他就会按照行动指南上的步骤去进行工作,不完成是不会结束的。但有时我们需要增加一些机制,例如老板突然来电话了,说转账的对方是个骗子,需要赶紧停止转账,那张三该如何通知李四停止呢?这就涉及到我们的停止线程的方式了。
目前常见的有以下两种方式:
Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记。
示例代码(方法一):
package Thread;
/**
* 线程的中断
*/
public class Demo {
private static boolean isQuit=false;
public static void main(String[] args) {
Thread t=new Thread(()->{
while(!isQuit){
System.out.println("hello thread!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
//只要把这个isQuit设为true,此时这个循环就退出了,进一步的这个run方法就执行完了,再进一步说就是这个线程执行结束了
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
isQuit=true;
System.out.println("终止t线程执行");
}
}
package Thread;
public class Demo1 {
public static void main(String[] args) {
Thread t=new Thread(()->{
while(!Thread.currentThread().isInterrupted()){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//在主线程中,调用interrupt方法,来中断这个线程
t.interrupt();//让t线程被中断
}
}
结果图如下:
由上面的结果图效果可知,使用t.interrupt() 方法并没有成功让t这个线程中断,具体原因见下图:
那么该如何解决这个问题呢,只需在触发异常后退出循环即可,如以下代码所示:
while(!Thread.currentThread().isInterrupted()){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
//当我们触发异常后立即退出循环
break;
}
}
});
多个线程之间,调度顺序是不确定的。由于线程之间的执行是按照调度器来安排的,而这个过程我们可以视为是“无序,随机的”,但是有些时候,我们需要能够控制线程之间的顺序,而线程等待就是其中一种控制线程执行顺序的手段。此处的线程等待主要是控制线程结束的先后顺序。
基本方法及说明:
代码示例如下:
package Thread;
public class Demo2 {
public static void main(String[] args) {
Thread t=new Thread(()->{
for(int i=0;i<5;i++){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
//在主线程中使用等待操作来等待t线程执行结束
try {
//t.join();//默认情况下是死等
t.join(1000);//进入join也会产生阻塞,但阻塞不会一直持续下去,可以执行等待时间,最长等待多久,若超过了时间则此时join直接返回
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上述代码中,调用这个方法的线程是main线程,是针对t这个线程对象调用的,此时就是让main等待t,调用join后,main线程就会进入阻塞状态(暂时无法在cpu上执行)。
因为线程的调度是不可控的,所以,这个方法只能保证实际休眠时间是大于等于参数设置的休眠时间的。
方法 | 说明 |
---|---|
public static void sleep(long millis) throws InterruptedException | 休眠当前线程 millis毫秒 |
public static void sleep(long millis, int nanos) throwsInterruptedException | 可以更高精度的休眠 |
示例代码如下:
package Thread;
public class Demo4 {
public static void main(String[] args) throws InterruptedException {
System.out.println(System.currentTimeMillis());
Thread.sleep(3*1000);
System.out.println(System.currentTimeMillis());
}
}
方法 | 说明 |
---|---|
public static Thread currentThread(); | 返回当前线程对象的引用 |
哪个线程调用的这个currentThread方法,就获取到的是哪个线程的实例。
示例代码如下:
package Thread;
public class Demo3 {
public static void main(String[] args) {
Thread t=new Thread(){
@Override
public void run() {
// System.out.println(Thread.currentThread().getName());//得到t这个线程的名字
System.out.println(this.getName());对于这个代码来说,是通过继承Thread的方式来创建线程,所以此时在run方法中,直接通过this拿到的就是当前Thread的实例
}
};
t.start();
System.out.println(Thread.currentThread().getName());//得到main线程的名字
}
}