守护线程
守护线程是用来守护非守护线程的
非守护线程:就是平常写得线程、
一个应用程序必须有一个非守护线程
非守护线程一旦结束,守护线程就会自动消亡
thread.setDaemon(true);
死锁
死锁是指两个或者两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信二造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁线程。
手写一个死锁
class DeadLock implements Runnable { private boolean flag;//标记属性 private Object obj1;//锁住的对象 private Object obj2;//锁住的对象 public DeadLock(boolean flag, Object obj1, Object obj2) { this.flag = flag; this.obj1 = obj1; this.obj2 = obj2; } @Override public void run() { //true if (flag) {//如果设置为true,就让线程1进入到if语句中 synchronized (obj1) {//锁住的是obj1对象 //线程1持有obj1锁 System.out.println(Thread.currentThread().getName() + "拿到了锁1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("等待锁2的释......"); //我想在线程1中去使用线程2中的那个锁2 obj2 //线程1里面想用obj2锁对象 //也走不下去了 //线程1也没有释放obj1 synchronized (obj2) { System.out.println("123"); System.out.println(Thread.currentThread().getName() + "拿到了锁1"); } } } if (!flag) {//如果设置为false,就让线程2进入到if语句中 synchronized (obj2) {//锁住的是obj2对象 //线程2持有obj2这个锁 System.out.println(Thread.currentThread().getName() + "拿到了锁2"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("等待锁1的释......"); //只有obj1释放掉以后,才能在线程2中对obj1加锁 //想一个问题,如果obj1锁对象没有被释放,那么下面这个代码 //线程2中去锁obj1 //在这等着呢 往下走不下去了 线程2没有释放obj2对象 synchronized (obj1) { System.out.println("456"); System.out.println(Thread.currentThread().getName() + "拿到了锁1"); } } } } } public class Demo1 { public static void main(String[] args) { Object obj1 = new Object(); Object obj2 = new Object(); //线程1可以进入到run方法中 if (flag) DeadLock deadLock = new DeadLock(true, obj1, obj2); new Thread(deadLock, "线程1").start(); //线程2 可以进入倒run方法中if(!flag) DeadLock deadLock1 = new DeadLock(false, obj1, obj2); new Thread(deadLock1, "线程2").start(); } }
线程生命周期
1)新建:当一个Thread类或其子类的对象被声明并创建时。新生的线程对象属于新建状态。
(2)就绪(可运行状态):处于新建状态的线程执行start()方法后,进入线程队列等待CPU时间片,该状态具备了运行的状态,只是没有分配到CPU资源。
(3)运行:当就绪的线程分配到CPU资源便进入运行状态,run()方法定义了线程的操作。
(4)阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时终止自己的的执行,进入阻塞状态。
(5)死亡:当线程执行完自己的操作或提前被强制性的终止或出现异常导致结束,会进入死亡状态。
和线程相关的Object类下面的方法
Object类下面的方法:
public final void wait() throws InterruptedException
void | notify() 唤醒正在等待对象监视器的单个线程。 |
---|---|
void | notifyAll() 唤醒正在等待对象监视器的所有线程。 |
总结:至少两个线程,其中一个线程中使用对象.wait() 那么这个线程就会阻塞,代码不会往下执行了。如何想让这个线程往下执行呢?再开另外一个线程,使用对象.notify()去唤醒另外那个等待线程。
案例
//创建这个类的目的,就是实例化出来对象,然后拿这个对象 //调用wait方法和notify方法 //wait方法和notify方法是object对象的方法 class Message { private String message; public Message(String message) { this.message = message; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } @Override public String toString() { return "Message{" + "message='" + message + '\'' + '}'; } } //导致当前线程等待,直到另一个线程调用该对象的[`notify()` class WaiterThread implements Runnable { //想一个问题?WaiterThread 使用message对象调用 //wait() 咋解决? private Message msg; public WaiterThread(Message msg) { this.msg = msg; } @Override public void run() { //先获取当前线程名字 String name = Thread.currentThread().getName(); System.out.println(name + "等待唤醒时间:" +System.currentTimeMillis()); //让等待线程去阻塞,去等待 这个线程执行不下去了 //锁的是msg对象 synchronized (msg) {//为啥是哟个wait的时候要加锁?等会将 try { msg.wait();//代码走到这,当前这个线程阻塞,不往下走了 //咱们得想办法让这个等待线程继续执行下去,咋办? //在另外一个线程中去调用notify方法那么等待线程就会执行下去 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("123"); System.out.println(name + "被唤醒的时间:" + System.currentTimeMillis()); } } } //唤醒线程 class NotifyThread implements Runnable { //也要用同一个对象是WaiterThread线程中同一个对象调用notify()方法 private Message msg; public NotifyThread(Message msg) { this.msg = msg; } @Override public void run() { try { //我的想法是不能先让唤醒线程执行 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println(name + "开始唤醒等待线程"); synchronized (msg) { msg.setMessage("我是修改之后的message值"); //msg.notify(); msg.notifyAll();//唤醒所有线程 } } } public class Demo1 { public static void main(String[] args) { Message message = new Message("我是message属性"); WaiterThread waiterThread = new WaiterThread(message); NotifyThread notifyThread = new NotifyThread(message); //如果等待线程好几个 咋办呢? new Thread(waiterThread, "等待线程1").start(); new Thread(waiterThread, "等待线程2").start(); new Thread(waiterThread, "等待线程3").start(); new Thread(notifyThread, "唤醒线程").start(); //等待线程等待唤醒时间:1660187660718 等待线程 //唤醒线程开始唤醒等待线程 唤醒线程 //123 等待线程 //等待线程被唤醒的时间:1660187661740 等待线程 //这叫线程之间的通信问题!!! } }
生产者消费者模式
生活中例子:
卖家:BYD汽车厂商
买家: 咱们75名学生
想买一辆 比亚迪汉 , 告知汽车厂商我要买车。这个学虎会进入到等待状态
等到比亚迪厂家造完车以后,再通知来提车。如果比亚迪厂家有现车,就直接提车。
如果产品需要生产的话,消费者进入到阻塞状态 wait
如果产品不需要生产的话,消费者直接购买
这些会牵涉到咱们刚讲过的wait和notify方法!!!
只不过业务逻辑又复杂了啊
//为啥要新建这类Goods? //还记得上午讲的Message类 //因为两个线程要通信。这个Goods就是通信的桥梁!!! //goods.wait() 消费者等待 //goods.notoify() 生产者唤醒消费者 class Goods { private String name;//商品名字 private double price;//商品价格 private boolean isProduct;// //isProduct是否有这个商品, true 没有这个产品需要生产 //false 有这个产品,不需要生产 //有参构造 public Goods(String name, double price, boolean isProduct) { this.name = name; this.price = price; this.isProduct = isProduct; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public boolean isProduct() { return isProduct; } public void setProduct(boolean product) { isProduct = product; } @Override public String toString() { return "Goods{" + "name='" + name + '\'' + ", price=" + price + ", isProduct=" + isProduct + '}'; } } //接下来搞两个线程?一个消费者线程 一个是生产者线程 class Customer implements Runnable { //为啥要定义这个goods变量? 因为两个线程要共享同一个资源!!! private Goods goods; public Customer(Goods goods) { this.goods = goods; } @Override public void run() { //写业务逻辑,业务比较麻烦 while (true) {//一直消费 synchronized (goods) { //goods.isProduct true 需要生产,没有商品 false 不需要生产 if (!goods.isProduct()) { //不需要生产的,消费者直接购买 System.out.println("消费者购买了:" + goods.getName() + ",价格为:" + goods.getPrice()); //购买完以后 商品没有了 将isProduct这个变量修改为true goods.setProduct(true); //大家有没有想过这个问题?消费者在购买的时候,生产者等待 //唤醒生产者去生产车了 goods.notify();//可以先防一下,等会再看!!! } else { //需要生产的!!!,没商品(咋办) //消费者进入到阻塞状态!!! try { goods.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } class Producter implements Runnable { //为啥要定义这个goods变量? private Goods goods; public Producter(Goods goods) { this.goods = goods; } @Override public void run() { int count = 0; //生产者,业务逻辑比较麻烦 while (true) {//你一直消费,我一直生产 synchronized (goods) { if (goods.isProduct()) {//true 需要生产的!! //造车,就是赋值 对goods对象进行赋值 //奇数造一种车, 偶数造另外一种车 if (count % 2 == 0) {//偶数 goods.setName("奥迪A8"); goods.setPrice(78.9); } else {//奇数 goods.setName("五菱大光"); goods.setPrice(12.9); } //生产一辆车,一定要记得有车了 //标记就改为 false 就证明不需要再生产了 goods.setProduct(false); System.out.println("生产者生产了:" + goods.getName() + ",价格为:" + goods.getPrice()); count++; //生产完以后,唤醒消费者。让消费者去提车 goods.notify(); } else { //不需要生产 //不需要生产 有货,生产着歇着,阻塞 try { goods.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } public class Demo1 { public static void main(String[] args) { Goods goods = new Goods("东风41", 67.8, false); Producter producter = new Producter(goods); new Thread(producter).start(); Customer customer = new Customer(goods); new Thread(customer).start(); /** * 谁先抢到线程?消费者?还是生产者? * //如果是消费者抢到执行权,不用说!!!直接打印消费者购买了东风 * //如果生产者抢到执行权,生产者wait,那就意味着必须去执行消费者线程 * 消费者购买了:东风41,价格为:67.8 * //此时isProduct是true 需要时生产 * 还是消费者和生产者抢这个执行权 * //假如生产者抢到了 就会打印生产者生产了啥。 * //假如消费者抢到了执行权,消费者进入倒阻塞状态!!! * //消费者进入倒阻塞,那么肯定生产者得执行了 * 生产者生产了:奥迪A8,价格为:78.9 * * 还是两个线程抢这个执行权 * 消费者购买了:奥迪A8,价格为:78.9 * 生产者生产了:五菱大光,价格为:12.9 * 消费者购买了:五菱大光,价格为:12.9 * 生产者生产了:奥迪A8,价格为:78.9 * 消费者购买了:奥迪A8,价格为:78.9 * 生产者生产了:五菱大光,价格为:12.9 * 消费者购买了:五菱大光,价格为:12.9 * 生产者生产了:奥迪A8,价格为:78.9 * 消费者购买了:奥迪A8,价格为:78.9 */ } }