Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。
线程创建
前面我们已经讲过了如何使用Thread 类创建多线程,下面我们来讲一下Thread创建多线程不同的几种的几种方法
Thread() 创建线程对象
Thread t1 = new Thread();
Thread(Runnable target) 使用 Runnable 对象创建线程对象
Thread t2 = new Thread(new MyRunnable());
Thread(String name) 创建线程对象,并命名
Thread t3 = new Thread("这是我的名字");
Thread(Runnable target, String name) 使用 Runnable 对象创建线程对象,并命名
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");
线程中断
之前我们已经看到了如何通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。这里我们还需要调用start方法来启动线程
start方法启动线程
package Thread;
public class ThreadDemo6 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (true) {
System.out.println("hello t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"我的线程");
t.start();
}
}
使用自定义的变量来作为标志位.
package Thread;
public class ThreeDemo9 {
public static boolean isQuit=false;
public static void main(String[] args) {
//boolean isQuit=false;变量捕获此处若被final修饰或未被final修饰未改变值则可以捕获
Thread t=new Thread(()->{
while (!isQuit){
System.out.println("hello t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t线程终止");
});
t.start();
//在主线程上修改isQuin
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
isQuit=true;
}
}
使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位.
package Thread;
public class ThreadDemo10 {
public static void main(String[] args) {
Thread t=new Thread(()->{
//currentThread是获取到当前线程案例
//此处currentThread得到的对象就是t
//isInterrupted就是t对象自带的一个标志
while (!Thread.currentThread().isInterrupted()){
System.out.println("hello t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
//此处interrupt会通过报错将阻塞状态sleep唤醒并同时将标志位清空变为false
break;
}
}
});
t.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//把t内部的标志位给设置成true
t.interrupt();
}
}
thread 收到通知的方式有两种:
- 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以InterruptedException 异常的形式通知,清除中断标志当出现InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法.
可以选择忽略这个异常, 也可以跳出循环结束线程.- 否则,只是内部的一个中断标志被设置,thread 可以通过
Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志这种方式通知收到的更及时,即使线程正在 sleep 也可以马上收到。
线程等待
我们编写一个简单的线程代码,让t线程和main线程同时运行此时我们会发现mian线程会优先打印t线程后打印,而实际上线程的运行是并发并行随机的,可能这次是mian线程先运行,但下次就不一定了
package Thread;
public class ThreadDemo11 {
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
System.out.println("hello t");
});
t.start();
System.out.println("hello main");
}
}
等待一个线程-join()
package Thread;
public class ThreadDemo11 {
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
System.out.println("hello t");
});
t.start();
t.join();
System.out.println("hello main");
}
}
此时我们通过jion方法可以让t线程先运行再运行mian线程,而jion方法就是等待一个线程完成它的工作后,才能进行自己的下一步工作
线程休眠
因为线程的调度是不可控的,所以,这个方法只能保证实际休眠时间是大于等于参数设置的休眠时间的
public static void sleep(long millis) throws InterruptedException 休眠当前线程 millis毫秒
public static void sleep(long millis, int nanos) throws InterruptedException 可以更高精度的休眠
其实休眠线程的方法,我们上面就有使用到的,为了可以清晰的看见线程的打印顺序
package Thread;
public class ThreadDemo11 {
public static void main(String[] args) throws InterruptedException {
System.out.println(System.currentTimeMillis());
Thread.sleep(3 * 1000);
System.out.println(System.currentTimeMillis());
}
这里的 currentTimeMillis()方法是返回从1970年1月1日午夜(UTC)开始到当前时间的毫秒值而中间休眠了3000毫秒,再次打印就经历了3000毫秒再次打印
获取线程引用
public static Thread currentThread(); 返回当前线程对象的引用
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
System.out.println(thread.getName());
}
}
通过 currentThread();我们就可以获取到线程状态 ,此时我们获取到的就是mian线程
getState()方法获取当前线程状态
public static void main (String[] args) {
Thread t = new Thread(()->{
System.out.println("hello Thread");
});
System.out.println(t.getState());
}