Thread类
线程指的是一系列执行的程序。JVM允许应用同一时刻多个线程并行执行,那如何来管理多个线程呢?——Thread类
Thread类用于操作线程,是所有涉及到线程操作(如并发)的基础。
Thread类是JVM用来管理线程的一个类,每一个线程都有一个唯一的Thread类与之对应。
Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。
常用API
静态方法:作用在当前代码行所在的线程
实例方法:作用在调用的线程对象上
设置线程名
我们在使用多线程的时候,想要查看线程名的方法很简单是:Thread.suurentThread().getName()
如果没有做什么设置,我们得到的线程的名字为:主线程为main,其他的线程名称为Thread-X
通常情况下为了更加清晰的区别出各个线程,可以使用以下两种方式来设置线程名称:
- Thread类给我们提供了构造方法,在创建线程时就将线程名车给传入
- 我们可以通过setName(String name)的方法来改掉线程的名称。
public class MyThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread,"学习");//thread1线程
Thread thread2 = new Thread(myThread,"努力学习");//thread2线程
thread1.setName("你好");
thread2.setName("多线程");
thread1.start();
thread2.start();;
System.out.println(Thread.currentThread().getName());//main
}
}
守护线程
守护线程是为其他线程服务的,垃圾回收线程就是守护线程
守护线程的特点:
- 如果别的用户线程执行完了,虚拟机就会退出,守护线程也就会被停止。
- 守护线程作为一个服务线程,如果没有服务对象就没有必要再继续运行。
设置守护线程:setDaemon(boolean on)
- 在线程启动前设置为守护线程(如果在启动了设置守护线程,会抛出异常)
- 使用守护线程不要访问共享资源
- 守护线程中产生的新线程也是守护线程
public class TestDaemon {
public static void main(String[] args) {
First first = new First();
Second second = new Second();
Thread thread1 = new Thread(first);
thread1.setDaemon(true);//设置为守护线程
thread1.start();
new Thread(second).start();
}
}
class First implements Runnable{
@Override
public void run() {
while (true){
System.out.println("你一直在学习");
}
}
}
class Second implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("你在学习Java");
}
}
}
线程优先级
Java提供了一个线程调度器来监控程序中启动之后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。
线程优先级的范围:1-10
改变或获取优先级: getPriority(), setPriority(int x)
优先级低的只是意味着获得调度的概率低,并不是优先级低的就不会被调用。这些都要取决于CPU的调度。
线程生命周期
线程的三个基本状态:执行、就绪和阻塞
sleep方法
调用sleep方法会进入计时等待状态,等时间到了,进入的是就绪状态而并非是运行状态!
public class TestThreadSleep {
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
final int n =i;
//子线程休眠3秒钟,同时执行
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println(n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
//main线程和子线程同时执行
System.out.println("OK");
}
}
yield方法
调用yield方法会先让别的线程执行,但是不确保真正让出。
让当前线程让步,从运行态转变为就绪态
意思是:我有空,可以的话,让你们先执行
public class TestYield {
public static void main(String[] args) {
Thread[] threads = new Thread[5];
for (int i = 0; i < 5; i++) {
final int n =i;
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(n);
}
});
}
for (Thread t :threads){
t.start();
}
//子线程执行完,再执行主线程代码
while (Thread.activeCount()>2){//当前活跃的线程数量只要大于2,就让当前线程让步
Thread.yield();//让当前线程让步
}
System.out.println("OK");
}
}
join方法
调用join方法,会等待该线程执行完毕后才执行别的线程,让当前线程无条件等待
public class TestJoin {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t");
}
});
t.start();
t.join();
//当前线程——main线程无条件等待,直到t线程执行完毕之后,当前线程再继续往后执行
System.out.println("main");
}
}
interrupt方法——中断线程
线程的中断在之前的版本有stop方法,但是被设置过时了。现在已经没有强制线程终止的方法了。
现在一般使用interrupt来请求终止线程:
- interrupt不会真正停止一个线程,仅仅是给这个线程发一个信号告诉它,应该要结束了
- 具体到底是中断还是继续运行,应该由被通知的线程自己进行处理。
Thread t1 = new Thread( new Runnable(){
public void run(){
// 若未发生中断,就正常执行任务
while(!Thread.currentThread.isInterrupted()){
// 正常任务代码……
}
// 中断的处理代码……
doSomething();
}
} ).start();
调用interrupt()并不是要真正终止掉当前线程,仅仅是设置了一个中断标志。
这个中断标志可以给我们用来判断什么时候该干什么活!
什么时候中断由我们自己来决定,这样就可以安全地终止线程了!
interrupt方法压根是不会对线程的状态造成影响的,它仅仅设置一个标志位罢了
interrupt线程中断还有另外两个方法——检查该线程是否被中断
- 静态方法:interrupted()——>调用后,会清除中断标志位
- 实例方法:isInterrupted()——>调用后,不会清除中断标志位
- 通过 thread 对象调用 interrupt() 方法通知该线程停止运行
- thread 收到通知的方式有两种:
- 如果线程调用了 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通知,清除中断标志
- 否则,只是内部的一个中断标志被设置,thread 可以通过
- Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
- Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志
public class InterruptThreadDemo {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
/* try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("以异常的形式退出");//如果以异常的形式退出,就会清除中断标志位,变为false
}*/
for (int i = 0; i < 20; i++) {
// System.out.println(Thread.currentThread().isInterrupted());//调用isInterrupted(),不会清楚中断标志位
System.out.println(Thread.interrupted());//清除中断标志位
}
}
});
thread.start();
thread.interrupt();//中断标志位变为true
}
}
线程状态
线程的状态是一个枚举类型Thread.State
线程状态的转变: