Version: Next
线程状态
线程五大状态
- 创建状态
- 就绪状态
- 阻塞状态
- 运行状态
- 死亡状态
线程方法
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在制定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的线程对象并执行其他线程 |
void interrupt() | 中断线程,别用这个方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
线程停止
- 不推荐使用JDK提供的
stop()
、destroy()
方法- 推荐线程自己停止下来
- 建议使用一个标志作为终止变量,当flag = false,则终止线程运行
public class TestStop implements Runnable {//1.线程中定义线程体使用标识private boolean flag = true;@Overridepublic void run() {//2.线程体使用该标识while (flag) {System.out.println("running Thread");}}//3.对外提供方法改变标识public void stop() {this.flag = false;}}
public class Demo06TestStop implements Runnable {
private boolean flag = true;
@Override
public void run() {
while (flag) {
System.out.println("线程运行中...");
}
}
public void stop() {
this.flag = false;
}
public static void main(String[] args) {
Demo06TestStop t = new Demo06TestStop();
Thread t1 = new Thread(t);
t1.start();
for (int i = 0; i < 10000; i++) {
if (i == 9000) {
t.stop();
}
}
}
}
线程休眠-sleep
sleep(时间)
指定当前线程阻塞的毫秒数sleep
存在异常InterruptedException
sleep
时间达到后线程进入就绪状态sleep
可以模拟网络延时,倒计时等- 每一个对象都有一个锁,
sleep
不会释放锁Thread.sleep(200);
- 模拟倒计时
public class Demo07TestSleep {
public static void tTen() throws InterruptedException {
int seconds = 10;
while (true) {
Thread.sleep(1000);
System.out.println(seconds--);
if (seconds <= 0) {
break;
}
}
}
public static void main(String[] args) throws InterruptedException {
tTen();
}
}
- 打印系统时间
public static void main(String[] args) throws InterruptedException {
Date startTime = new Date(System.currentTimeMillis());
while (true) {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:ss:mm")
.format(startTime));
startTime = new Date(System.currentTimeMillis()); //更新时间
}
}
线程礼让-yield
- 礼让线程,让当前正在执行的线程暂停,但不阻塞
- 将线程从运行状态转为就绪状态
- 让CPU重新调度,礼让不一定成功,具体结果取决于CPU
public class Demo08Yield implements Runnable{
public static void main(String[] args) {
Demo08Yield o1 = new Demo08Yield();
Demo08Yield o2 = new Demo08Yield();
new Thread(o1,"thread1").start();
new Thread(o2,"thread2").start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程开始执行...");
Thread.yield();
System.out.println(Thread.currentThread().getName() + "线程停止执行");
}
}
礼让成功:
thread2线程开始执行...
thread1线程开始执行...
thread2线程停止执行
thread1线程停止执行
线程强制执行-join
- Join合并线程,待此线程执行完毕后,再执行其他线程,其他线程阻塞
- 可以想象为插队
public class Demo09Join implements Runnable {
@Override
public void run() {
for (int i = 0; i < 300; i++) {
System.out.println("线程中的vip来了..." + i);
}
}
public static void main(String[] args) throws InterruptedException {
Demo09Join o1 = new Demo09Join();
Thread thread1 = new Thread(o1);
thread1.start();
//主线程
for (int i = 0; i < 1000; i++) {
if (i == 200) {
//当主线程运行到200次时,强制切入我们自己的线程
thread1.join();
}
System.out.println("主线程...." + i);
}
}
}
主线程....195
主线程....196
主线程....197
线程中的vip来了...226
线程中的vip来了...227
线程中的vip来了...228
线程中的vip来了...229
主线程....198
主线程....199
线程中的vip来了...230
线程中的vip来了...231
线程中的vip来了...232
线程中的vip来了...233
线程中的vip来了...234
线程中的vip来了...235
线程中的vip来了...236
线程中的vip来了...237
线程中的vip来了...238
线程中的vip来了...239
线程中的vip来了...240
线程中的vip来了...241
线程中的vip来了...242
线程中的vip来了...243
线程中的vip来了...244
线程中的vip来了...245
线程中的vip来了...246
线程中的vip来了...247
线程中的vip来了...248
线程中的vip来了...249
线程中的vip来了...250
线程中的vip来了...251
线程中的vip来了...252
线程中的vip来了...253
线程中的vip来了...254
线程中的vip来了...255
线程中的vip来了...256
线程中的vip来了...257
线程中的vip来了...258
线程中的vip来了...259
线程中的vip来了...260
线程中的vip来了...261
线程中的vip来了...262
线程中的vip来了...263
线程中的vip来了...264
线程中的vip来了...265
线程中的vip来了...266
线程中的vip来了...267
线程中的vip来了...268
线程中的vip来了...269
线程中的vip来了...270
线程中的vip来了...271
线程中的vip来了...272
线程中的vip来了...273
线程中的vip来了...274
线程中的vip来了...275
线程中的vip来了...276
线程中的vip来了...277
线程中的vip来了...278
线程中的vip来了...279
线程中的vip来了...280
线程中的vip来了...281
线程中的vip来了...282
线程中的vip来了...283
线程中的vip来了...284
线程中的vip来了...285
线程中的vip来了...286
线程中的vip来了...287
线程中的vip来了...288
线程中的vip来了...289
线程中的vip来了...290
线程中的vip来了...291
线程中的vip来了...292
线程中的vip来了...293
线程中的vip来了...294
线程中的vip来了...295
线程中的vip来了...296
线程中的vip来了...297
线程中的vip来了...298
线程中的vip来了...299
主线程....200
主线程....201
主线程....202
锁控制
方法 | 是否释放锁 | 分析 |
---|---|---|
sleep() | 否 | 进入阻塞状态 |
wait() | 是 | 在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。 当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。 唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。 waite()和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。 |
join() | 是 | 等待调用join方法的线程结束,再继续执行。因为底层调用了wait() ,所以会释放锁 |
yield() | 否 | yield() 只是使当前线程重新回到可执行状态,不会释放锁,只是通知调度器自己可以让出cpu时间片,但只是建议,调度器也不一定采纳 |
观察线程状态
Thread.State线程状态可以处于下列状态之一:
NEW
尚未启动的线程处于此状态RUNNABLE
在Java虚拟机中执行的线程处于此状态BLOCKED
被阻塞等待监视器锁定的线程处于此状态WAITING
正在等待另一个线程执行特定动作的线程处于此状态TIMED_WAITING
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态TERMINATED
已退出的线程处于此状态一个线程可以在给定时间点处于一个状态。这些状态是不反应任何操作系统状态的虚拟机状态
public class Demo10State {
public static void main(String[] args) throws InterruptedException {
Thread.State state = null;
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("/////");
}, "thread1");
//观察状态
state = thread1.getState();
System.out.println(state);
//观察启动后
thread1.start();
state=thread1.getState();
System.out.println(state);
while (state != Thread.State.TERMINATED){
//只要线程不终止就一直输出线程状态
state = thread1.getState();
System.out.println(state);
Thread.sleep(200);
}
}
}
NEW
RUNNABLE
RUNNABLE
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
/////
TERMINATED
线程优先级
- Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行
- 线程的优先级用数字表示,范围
1~10
Thread.MIN_PRIORITY = 1;
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
- 使用以下方式改变或获取优先级
- 获取优先级:
getPriority()
- 更改优先级:
setPriority(int priorityNum)
public class Demo11Priority implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " --> " +
Thread.currentThread().getPriority());
}
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " --> " +
Thread.currentThread().getPriority());
Demo11Priority myClass = new Demo11Priority();
Thread t1 = new Thread(myClass,"Thread1");
Thread t2 = new Thread(myClass,"Thread2");
Thread t3 = new Thread(myClass,"Thread3");
Thread t4 = new Thread(myClass,"Thread4");
Thread t5 = new Thread(myClass,"Thread5");
//先设置优先级,再启动
t1.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.setPriority(9);
t2.start();
t3.setPriority(8);
t3.start();
t4.setPriority(6);
t4.start();
t5.setPriority(7);
t5.start();
}
}
main --> 5
Thread1 --> 10
Thread2 --> 9
Thread3 --> 8
Thread4 --> 6
Thread5 --> 7
caution
优先级低只是意味着获得调度的概率低,并不是优先级低就不会被优先调用,具体都是由CPU调度决定的
上下文切换
多线程编程中一般线程的个数都大于CPU核心的个数,而一个CPU核心在任一时刻只能被一个线程使用,为了让这些线程能得到有效执行,CPU采取的策略师为每个线程分配时间片并轮转的形式
当一个线程的时间片用完的时候会重新处于就绪状态,让给其他线程使用,这个过程就属于一次上下文切换
当前任务在执行完CPU时间片切换到另一个任务之前,会先保存自己的状态,以便下一次再切换回这个任务时,可以加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换
上下文切换通常是计算密集型的,也就是说,它需要相当可观的处理器时间,在每秒几十上百次的切换中,每次切换都需要纳秒级的时间。所以上下文切换对系统来说意味着消耗大量的CPU时间,事实上,可能是操作系统中时间消耗最大的操作
Linux相比其他操作系统有很多优点,其中一项就是,其上下文切换和模式切换的时间消耗非常少
守护线程 —— Daemon Thread
- 线程分为
用户线程
和守护线程
- 虚拟机不许确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如,后台记录操作日志、监控内存、垃圾回收等待..
setDaemon(Boolean enable) //true for daemon , false for normal
public class Demo12Daemon {
public static void main(String[] args) {
God god = new God();
Me me = new Me();
//讲上帝设置为守护线程
Thread godThread = new Thread(god, "god Thread");
godThread.setDaemon(true);
godThread.start();
//启动我自己
new Thread(me, "me Thread").start();
}
}
class Me implements Runnable {
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("我开心的活着的第" + i + "天");
}
System.out.println("=========安详的走了======");
}
}
class God implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("上帝保佑着我...");
}
}
}
我开心的活着的第36498天
我开心的活着的第36499天
上帝保佑着我...
=========安详的走了======
上帝保佑着我...
上帝保佑着我...
上帝保佑着我...
上帝保佑着我...