Thread类的基本用法:
1.创建子类,继承自Thread并且重写run方法:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("hello thread");
}
}
public class Demo1 {
public static void main(String[] args) {
// 最基本的创建线程的办法.
Thread t = new MyThread();
//调用了start方法才是真正的在系统中创建了线程,执行run方法
t.start();
}
}
2.创建一个类,实现Runnable接口再创建Runnable是实例传给Thread
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("hello");
}
}
public class Demo3 {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
}
}
3.匿名内部类
创建了一个匿名内部类,继承自Thread类,同时重写run方法,再new出匿名内部类的实例
public class Demo4 {
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run() {
System.out.println("hello");
}
};
t.start();
}
}
new的Runnable,针对这个创建的匿名内部类,同时new出的Runnable实例传给Thread的构造方法
public class Demo5 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
});
t.start();
}
}
4.lambda表达式 lambda代替Runnable
public class Demo6 {
public static void main(String[] args) {
Thread t = new Thread(() ->{
System.out.println("hello");
});
t.start();
}
}
线程的一些指标:
1.isDaemon();是否后台线程
后台线程不影响进程退出,不是后台线程会影响进程退出
2.isAlive();是否存活
在调用start前系统中是没有对应线程的,run方法执行完后线程就销毁了,t对象可能还存在
3.isinterrupted();是否被中断
run和start的区别 run单纯的只是一个普通方法描述了任务的内容 start则是一个特殊的方法,内部会在系统中创建线程
中断线程
线程停下来的关键是要让对应run方法执行完,对于main线程来说main方法执行完了才会终止
1.手动设置标志位 在线程中控制这个标志位就能影响到这个线程结束,但是此处多个线程共用一片虚拟空间,因此main线程修改的isQuit和t线程判断的isQuit是同一个值
public class Demo10 {
// 通过这个变量来控制线程是否结束.
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();
// 就可以在 main 线程中通过修改 isQuit 的值, 来影响到线程是否退出
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// main 线程在 5s 之后, 修改 isQuit 的状态.
isQuit = true;
}
}
2.使用Thread中内置的一个标志位来判定 Thread.interruted()这是一个静态方法 Thread.currentThread().isInterrupted()这是一个实例方法,其中currentThread能够获取到当前线程的实例
public class Demo7 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
while(!Thread.currentThread().isInterrupted()){
System.out.println("hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
// 当触发异常之后, 立即就退出循环~
System.out.println("这是收尾工作");
break;
}
}
});
t.start();
try{
Thread.sleep(5000);
}catch (InterruptedException e){
e.printStackTrace();
}
// 在主线程中, 调用 interrupt 方法, 来中断这个线程.
// t.interrupt 的意思就是让 t 线程被中断!!
t.interrupt();
}
}
需要注意的是调用这个方法t.interrupt()可能会产生两种情况:
1)如果t线程处在就绪就设置线程的标志位为true
2)如果t线程处在阻塞状态(sleep),就会触发一个InterruptExeception
线程等待
多个线程之间调度顺序是不确定的,有时候我们需要控制线程之间的顺序,线程等待就是一种控制线程执行顺序的手段,此处的线程等待只要是控制线程结束的先后顺序。
哪个线程中的join,哪个线程就会阻塞等待直到对应的线程执行完毕为止。
t.join();
调用这个方法的线程是main线程,针对t这个对象调用的此时就是让main等待t。
代码执行到join这一行就停下了,让t先结束然后main继续。t.join(10000);
join提供了另一个版本为带一个参数的,参数为等待时间10s之后join直接返回不再等待
Thread.currentThread()
能够获取当前线程的应用,哪个线程调用的currentThread就获取到哪个线程的实例 对比this如下:
对于这个代码来说,通过继承Thread的方法来创建线程。此时run方法中直接通过this拿到的就是当前Thread的实例
public class Demo4 {
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
System.out.println(this.getName());
}
};
t.start();
}
}
然而此处this不是指向Thread类型,而是指向Runnable,Runnable只是一个单纯的任务没有name属性,要想拿到线程名字只能通过Thread.currentThread()
public class Demo5 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
//err
//System.out.println(this.getName());
//right
System.out.println(Thread.currentThread().getName());
}
});
t.start();
}
}