1、线程生命周期
- 新生状态(new):线程对象一旦创建就进入新生状态
Thread thread = new Thread(runnable);
- 就绪状态(runnable):当调用 start() 方法时,线程立即进入就绪状态,但不意味着立即调度执行
thread.start();
- 运行状态(running):CPU 调度之后,线程进入运行状态,线程才真正执行线程体的代码块
- 阻塞状态(blocked):当调用sleep、wait 或同步锁定时,线程进入阻塞状态,阻塞事件解除后,重新进入就绪状态,等待cpu调度执行
- 死亡状态(dead):线程中断或者结束,一旦进入死亡状态,就不能再次启动
2、停止线程
- 不推荐使用JDK提供的 stop() 和 destroy() ,已过时,也不推荐中断线程 interrupt()
public class TestThreadStop implements Runnable{
@Override
public void run() {
System.out.println("running...");
}
public static void main(String[] args) {
TestThreadStop testThreadStop = new TestThreadStop();
Thread thread = new Thread(testThreadStop);
thread.stop();
thread.destroy();
}
}
- 推荐线程自己停下来,建议使用一个标志位进行终止变量
public class TestThreadStop implements Runnable{
// 线程停止标识
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println(Thread.currentThread().getName() + "-" + i++);
}
}
// 对外提供标记改变的方法
public void stop(){
flag = false;
}
public static void main(String[] args) {
TestThreadStop runnable = new TestThreadStop();
Thread thread = new Thread(runnable);
thread.start();
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName() + "-" + i);
if (i == 888){
runnable.stop();
System.out.println("线程该停止了...");
}
}
}
}
3、线程睡眠 sleep()
public class TestSleep {
public static void main(String[] args) {
// 系统当前时间
Date startTime = new Date(System.currentTimeMillis());
while (true) {
try {
// 延迟1s
Thread.sleep(1000);
// 打印时间
System.out.println(new SimpleDateFormat("MM:ss:hh").format(startTime));
// 更新时间
startTime = new Date(System.currentTimeMillis());
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
总结:
- sleep(时间)指定当前线程阻塞的毫秒数
- sleep 存在异常 InterruptedException
- sleep 时间达到后线程进入就绪状态
- sleep 可以模拟网络延时、倒计时等
- 每一个对象都有一个锁,sleep 不会释放锁
4、线程让步 yield()
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"张三").start();
new Thread(myYield,"李四").start();
}
}
class MyYield implements Runnable{
public void run() {
System.out.println(Thread.currentThread().getName() + "start running...");
// 线程礼让
Thread.yield();
System.out.println(Thread.currentThread().getName() + "stop running...");
}
}
总结:
- 线程让步,让当前正在执行的线程暂停,但不阻塞
- 将线程从运行状态转为就绪状态
- 让cpu重新调度,线程让步不一定成功,取决于cpu调度
5、线程强制执行 join()
public class TestJoin implements Runnable{
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 0; i < 500; i++) {
if (i == 200){
thread.join();
}
System.out.println(Thread.currentThread().getName() + "--" + i);
}
}
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println(Thread.currentThread().getName() + "是VIP,来插队了--" + i);
}
}
}
总结:
- join 合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
- 把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程
- 线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B
6、观测线程状态 getState()
public class TestThreadState {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("-------分割线-------");
});
Thread.State state = thread.getState();
// NEW
System.out.println(state);
thread.start();
state = thread.getState();
// RUNNABLE
System.out.println(state);
// 只要线程不终止,就一直输出状态 TIMED_WAITING
// 终止后 输出 TERMINATED
while (state != Thread.State.TERMINATED){
try {
Thread.sleep(100);
state = thread.getState();
System.out.println(state);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
总结(查看JDK文档):
- NEW:创建线程对象,但未启动,处于此状态
- RUNNABLE:在 jvm 中执行的线程处于此状态
- BLOCKED:被阻塞等待监视器锁定的线程处于此状态
- WAITING:正在等待另一个线程执行特定动作的线程处于此状态
- TIMED_WAITING:正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
- TERMINATED:已退出的线程处于此状态
7、线程优先级
public class TestPriority 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());
TestPriority priority = new TestPriority();
Thread t1 = new Thread(priority);
Thread t2 = new Thread(priority);
Thread t3 = new Thread(priority);
Thread t4 = new Thread(priority);
Thread t5 = new Thread(priority);
Thread t6 = new Thread(priority);
Thread t7 = new Thread(priority);
// 默认优先级为5
t1.start();
t2.setPriority(Thread.MIN_PRIORITY);
t2.start();
t3.setPriority(Thread.MAX_PRIORITY);
t3.start();
t4.setPriority(3);
t4.start();
t5.setPriority(7);
t5.start();
t6.setPriority(8);
t6.start();
t7.setPriority(2);
t7.start();
}
}
总结:
- Java 提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调用哪个线程来执行
- 线程的优先级用数字表示,范围从0-10
- 优先级高低只是意味着获得调度的概率大小,并不是一定按照设定的大小来调度,一切取决于CPU
8、守护线程
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread godThread = new Thread(god);
Thread youThread = new Thread(you);
// 设置线程为守护线程,默认false
godThread.setDaemon(true);
godThread.start();
youThread.start();
}
}
class God implements Runnable{
@Override
public void run() {
while (true) {
System.out.println("信上帝,得永生!");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("我活了" + i + "年");
}
System.out.println("活了100年,生命结束!");
}
}
总结:
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕才会退出,但是不用等待守护线程执行完毕
- 守护线程一般用于后台记录操作日志,监控内存,垃圾回收等