文章目录
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190615193332317.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMDYzMTQx,size_16,color_FFFFFF,t_70)
新建状态(New)
当用new操作符创建一个线程后, 例如new Thread(),此时线程处在新建状态。 当一个线程处于新建状态时,线程中的任务代码还没开始运行。
就绪状态(Runnable)
也被称为“可执行状态”。一个新创建的线程并不自动开始运行,要执行线程,必须==调用线程的start()==方法。当调用了线程对象的start()方法即启动了线程,此时线程就处于就绪状态。
处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他就绪线程竞争CPU,只有获得CPU使用权才可以运行线程。比如在单核心CPU的计算机系统中,不可能同时运行多个线程,一个时刻只能有一个线程处于运行状态。对与多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度执行。
除了调用start()方法后让线程变成就绪状态,一个线程阻塞状态结束后也可以变成就绪状态,或者从运行状态变化到就绪状态。
运行状态(Running)
线程获取到CPU使用权进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。真正开始执行线程的run()方法的内容。
阻塞状态(Blocked)
线程在获取锁失败时(因为锁被其它线程抢占),它会被加入锁的同步阻塞队列,然后线程进入阻塞状态(Blocked)。阻塞状态的线程不会释放锁处于阻塞状态(Blocked)的线程放弃CPU使用权,暂时停止运行
public class AddNumber {
private int num=0;
public void add(String name) throws InterruptedException {
num=100; //这里num值改为100
Thread.sleep(1000); //线程暂睡眠1秒,即进入阻塞状态1秒
//伪代码:另一个线程恰巧在这一秒的时间里将num=100修改了num=200;
//一秒之后,线程苏醒,继续运行run方法。但此时从内存中读出来的num值是200
//对于该线程来说,这里的num=200就属于脏读。
System.out.println(num);
待其它线程释放锁之后,阻塞状态(Blocked)的线程将在次参与锁的竞争,如果竞争锁成功,线程将进入就绪状态(Runnable) 。比如调用线程的调用线程的sleep()方法
等待状态(WAITING)
或者叫条件等待状态,当线程的运行条件不满足时,通过锁的条件等待机制(调用锁对象的==调用线程的wait()==或显示锁条件对象的await()方法)让线程进入等待状态(WAITING)。处于等待状态的线程将不会被cpu执行,除非线程的运行条件得到满足后,其可被其他线程唤醒,进入阻塞状态(Blocked)。调用不带超时的Thread.join()方法也会进入等待状态。
限时等待状态(TIMED_WAITING)
限时等待是等待状态的一种特例,线程在等待时我们将设定等待超时时间,如超过了我们设定的等待时间,等待线程将自动唤醒进入阻塞状态(Blocked)或就绪状态(Runnable) 。在调用Thread.sleep()方法,带有超时设定的Object.wait()方法,带有超时设定的Thread.join()方法等,线程会进入限时等待状态(TIMED_WAITING)。
死亡状态(TERMINATED)
线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
使用退出标志中断
public class test1 {
public static volatile boolean exit =false; //退出标志
public static void main(String[] args) {
new Thread() {
public void run() {
System.out.println("线程启动了");
while (!exit) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程结束了");
}
}.start();
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
exit = true;//5秒后更改退出标志的值,没有这段代码,线程就一直不能停止
}
}
使用 interrupt 方法中断
interrupt() + isInterrupted()+InterruptedException
public class ExceptionThread extends Thread {
@Override
public void run() {
try {
throw new InterruptedException();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<10000;i++){
//线程中断并不意味着线程结束,interrupt()只是改变了【isInterrupted()方法的返回值】中断标志的状态--(并且抛出InterruptedException异常而已),它不影响run()方法的运行
if (this.isInterrupted()){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("捕捉到了异常:该线程被中断了");
//e.printStackTrace();
}
System.out.println("我发生了线程中断,突然 over 掉了");
break;
//return;
}
System.out.println(i);
}
}
}
测试代码
public class Run {
public static void main(String arg[]) throws InterruptedException {
ExceptionThread exceptionThread=new ExceptionThread();
exceptionThread.start();
//主线程的休眠不会影响子线程的执行
Thread.sleep(100);
//主线程休眠0.1秒后,对子线程exceptionThread执行中断操作
exceptionThread.interrupt();
}
}
使用stop方法中断
jdk中标为过期的方法,强烈不建议使用
强制让线程停止,则有可能使一些清理性的工作得不到完成。对锁定的对象进行了解锁,导致数据得不到同步的处理,出现数据不一致的问题
suspend()方法+resume()方法的缺点
suspend()方法暂停线程,resume()方法恢复线程----二者使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步的对象------常见于让a线程start()后(a线程得到了SynchronizedObjectSole对象的pstring()方法的锁)又suspend暂停a线程,但程序却忘了resume恢复a线程,就相当于a线程得到的那把锁的钥匙丢了。则锁就永远不会被释放了
public class SynchronizedObjectSole {
synchronized public void pstring(){
System.out.println("start");
if(Thread.currentThread().getName().equals("a")){
Thread.currentThread().suspend();
System.out.println("a永远suspend");
}
System.out.println("end");
}
}
公共的同步对象的独占代码测试
public class Run {
public static void main(String arg[]) throws InterruptedException {
final SynchronizedObjectSole sos=new SynchronizedObjectSole();
Thread thread1=new Thread(){
@Override
public void run(){
sos.pstring();
}
};
thread1.start();
Thread.sleep(1000);
Thread thread2=new Thread(){
@Override
public void run(){
System.out.println("线程2永远无法使用sos对象的pstring()方法,因为它被a线程独占了");
sos.pstring();
}
};
thread2.start();
}
}
中断的综合测试
public class test1 {
static volatile boolean flag = true;
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开始休眠");
try {
Thread.sleep(100 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束休眠,开始死循环");
while (flag) {
}
System.out.println("------------------子线程结束------------------");
}
});
thread.start();
Scanner scanner = new Scanner(System.in);
System.out.println("输入1抛出一个中断异常,输入2修改循环标志位,输入3判断线程是否阻塞,输入其他结束Scanner\n");
while (scanner.hasNext()) {
String text = scanner.next();
System.out.println("你输入了:" + text + "\n");
if ("1".equals(text)) {
thread.interrupt();
} else if ("2".equals(text)) {
flag = false; //如果不设为false,主线程结束后子线程仍在运行
} else if ("3".equals(text)) {
System.out.println(thread.isInterrupted());
} else {
scanner.close();
break;
}
}
System.out.println("------------------主线程结束------------------");
}
}
摘抄自:
1.https://www.cnblogs.com/myseries/p/10918819.html
2.https://baijiahao.baidu.com/s?id=1626410873162104506&wfr=spider&for=pc