【线程三】
线程三
1. 线程启动–start
是Java标准库提供的一个方法。
1.每个Thread对象,都只能start一次。
2. 每次如果想创建一个新的线程,都需要创建1个新的Thread对象(不能重复使用的)3. start: 是java.lang.Thread 类中,是一个本地(native)方法。作用是启动一个线程,调用系统的api。
run: 是线程的入口方法,无需手动调用。是Runnable接口中的一个抽象方法,也是Thread类的一个普通方法。我们在创建线程的时候,会重写Thread类的run方法,在使用Runnable接口时,实现run方法。
Thread t = new Thread(() ->{
System.out.println("hello t");
});
t.start();//会启动线程,使线程进入就绪状态
2. 等待线程—join
由于线程是随机调度,并发执行的。 所以,join–等待线程,就能够要求,多个线程之间,结束的先后顺序。
Thread t = new Thread(() ->{
for (int i = 0; i < 3; i++) {
System.out.println("hello thread");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("t 线程结束");
});
t.start();
t.join();
System.out.println("hello main");
上述代码,在main线程中,调用t.join,就是让主线程等待t线程。当执行到t.join() 的时候,此时,main线程会“阻塞等待”,一直到t线程执行完毕,join才能继续执行。join还提供了带参数的版本,指定“超出时间”,即等待的最大时间
t.join(3000);
线程本身的调度是以ms为级别的。相当于等待3秒
如果3秒之内,比如刚过了1秒,线程t就结束了,此时,join就会立即执行,不会等满3秒。
如果t线程超过了3秒,那么join也会继续执行下去,而不会在进行等待了。
3. 获取线程引用
public static Thread currentThread();
获取当前线程的引用。
即哪个线程调用了这个方法,返回哪个线程的引用,类似于我们学过的this关键字
4. 休眠当前线程—sleep
sleep:举个例子
比如,我的好朋友A,今天突然说要出差,我就没有办法在约A出来聚会了,即A就不能参与调度了。
类似于sleep
sleep(1000);
1000很有可能会比1000多一点。
当代码调用了sleep,相当于当前线程让出cpu资源,后续等时间到了,操作系统内核,把这个线程重新调度到CPU上,才能继续执行。 时间到了,是允许被调度,而不是立即执行了,至于什么时间执行,还是需要看操作系统的调度器的决定。
sleep(0);
特殊的写法:意味着让当前的线程,立即放弃CPU资源,等待操作系统重新调度。
5. 线程状态
Java线程是对操作系统的线程的封装。
1. NEW
含义 : 当我们创建好线程,即new了个Thread对象,但是还没有start ,即为NEW状态。
Thread t = new Thread(() ->{
for (int i = 0; i < 3; i++) {
System.out.println("hello thread");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("t 线程结束");
},"t1");
System.out.println(t.getName() + " " + t.getState());
//t.start();//还没有启动start

结果是NEW状态,上述代码,获取当前的线程状态 .getState()。
2. Terminated
含义:操作系统内核中的线程已经结束了,Thread对象还在。相当于“工作都完成了”
Thread t = new Thread(() ->{
for (int i = 0; i < 3; i++) {
System.out.println("hello thread");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("t 线程结束");
},"t1");
System.out.println(t.getName() + " " + t.getState());// t1 NEW
t.start();
//Thread.sleep(2000);
t.join();
System.out.println(t.getName() + " " + t.getState()); //t1 Terminated
上述代码,当我们执行完t线程的时候,在最后一行执行的线程状态就是 Terminated
3. runnable
含义: 就绪状态,要么是正在CPU上执行,要么是随时都可以去CPU上执行。
比如,去银行办理业务,你可以是正在安排的服务人员,也可能是正在排队等待服务的人。
Thread t = new Thread(() ->{
for (int i = 0; i < 3; i++) {
System.out.println("hello thread");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("t 线程结束");
},"t1");
t.start();
System.out.println(t.getName() + " " + t.getState());
runnable就是在启动线程之后,就是正在 CPU 上执行(运行中),也可能在等待 CPU 资源(就绪状态)。
4. time_waiting
指定时间的阻塞,线程的阻塞(不参与CPU调度,不继续执行了),阻塞的时间是有上限的。
、线程是会在Thread.sleep(1000),wait,join 等进行阻塞等待,等待超时会就会自动唤醒。
线程调用 Thread.sleep(1000); 线程进入 TIMED_WAITING 状态 1 秒。
5. waiting
死等,没有超出时间的阻塞等待。是需要其他线程去主动唤醒的。
调用 object.wait();,线程进入 WAITING 状态。
6. blocked
也是一种阻塞状态,比较特殊,由于死锁导致的阻塞。
后续线程安全问题,会进行详细解答。
总结
在深入理解线程状态之后,我们对之后代码的bug就会很好进行调试。可以通过jconsole,查看当前所有的线程。当我们看到线程状态的不同,会有不一样的代码理解:
- time_waiting / waiting 怀疑是不是代码的某个方法产生了阻塞,没有即使被唤醒。
- block 代码中是否出现死锁,考虑线程安全问题。
- runnable 线程本身是没有问题的,考虑某些条件是不是没有触发。
NEW(创建 Thread)→ RUNNABLE(start() 启动,执行 run())→ 若竞争锁失败则进入 BLOCKED → 获取锁后执行 sleep() 进入 TIMED_WAITING → 唤醒后执行 wait() 进入 WAITING → 被 notify() 唤醒后回到 RUNNABLE → run() 执行完毕后进入 TERMINATED。
更多推荐



所有评论(0)