线程状态(生命周期)与线程同步
一.线程的状态
线程的状态:
新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
就绪:处于新建状态的线程调用start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没
分配到CPU资源
运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能,但不可直接调用run方法
阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态
死亡:线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束
二.改变线程状态常用方法
public class ThreadDemo extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%5==0){
Thread.yield();//线程主动让步(让出cpu执行权)
}
try {
Thread.sleep(1000);//让线程休眠指定的时间,进入阻塞状态
//(此处不能throw/throws因为Thread中run方法没有throws)
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
//线程的运行状态
public class Test {
public static void main(String[] args) {
ThreadDemo t=new ThreadDemo();//创建线程,进入新建状态
t.setName("线程1");
t.start();//1.启动线程,使线程进入就绪状态,随时等待cpu的加载
//2.线程进入运行状态,获取cpu的使用权
//3.当线程失去cpu的使用权时线程进入阻塞状态,当其他线程进行完后,重新进入就绪状态
//4.当线程中所有的任务执行完成后,进入死亡状态(销毁)
//t.stop();//对线程进行销毁
try {
t.join();//线程合并,即等待t线程执行完后,再执行另一个线程
// (应用场景,另一个线程中需要使用到第一个线程中数据)
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadDemo t1=new ThreadDemo();
t1.setName("线程2");
t1.start();
t1.stop();//对线程进行销毁
}
}
1.start();//1.启动线程,使线程进入就绪状态,随时等待cpu的加载
2.stop();//对线程进行销毁
3.yield();//线程主动让步(只是有概率,并非绝对让出cpu执行权)
4.join();//线程合并,即等待t线程执行完后,再执行另一个线程 (应用场景,另一个线程中需要使用到第一个线程中数据)
5.sleep();//让线程休眠指定的时间,进入阻塞状态
三.线程的分类(守护线程)
线程通常分为用户线程和守护线程
区别:守护线程就像是整个线程的看守员,只有当所有用户线程运行结束后,守护线程才会随着JVM一起结束工作
守护线程的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器)
public class Test {
public static void main(String[] args) {
GuardianThread gt=new GuardianThread();
Thread thread=new Thread(gt,"守护线程");
thread.setDaemon(true);//设置守护线程(就像GC回收机制一样)
//只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作
thread.start();
Thread thread1=new Thread(gt,"线程1");
thread1.start();
}
}
注意:设置线程为守护线程必须在启动线程之前,否则会跑出一个IllegalThreadStateException异常
四.线程同步
1.并行与并发
并行:多个cpu执行多个任务(多个人做多个事)
**并发:一个cpu(采用时间片方法)执行多个任务(一个人做多个事情) ** eg:就像我们买票一样,几千人抢几百张票
2.多线程同步
多个线程同时读写同一份共享资源时,可能会引起冲突。所以引入线程“同步”机制,即各线程间要有先来后到;
通常我们会使用(排队+锁)的方式实现:
几个线程之间要排队,一个个对共享资源进行操作,而不是同时进行操作;
为了保证数据在方法中被访问时的正确性,在访问时加入锁机制
,可能会引起冲突。所以引入线程“同步”机制,即各线程间要有先来后到;
通常我们会使用(排队+锁)的方式实现:
几个线程之间要排队,一个个对共享资源进行操作,而不是同时进行操作;
为了保证数据在方法中被访问时的正确性,在访问时加入锁机制
本节中单独列出lock锁和 synchronized 同步监视器的加锁方式