当前位置: 首页> 娱乐> 八卦 > 商务网站开发_博达网站建设教程_百度指数十年_长尾关键词挖掘词工具

商务网站开发_博达网站建设教程_百度指数十年_长尾关键词挖掘词工具

时间:2025/7/16 2:48:26来源:https://blog.csdn.net/2303_77535762/article/details/145998695 浏览次数:0次
商务网站开发_博达网站建设教程_百度指数十年_长尾关键词挖掘词工具

【JavaEE】wait 、notify 和单例模式

  • 一、引言
  • 一、wait()方法
  • 二、notify()方法
  • 三、notifyAll()方法
  • 四、wait()和sleep()对比
  • 五、单例模式
      • 5.1 饿汉模式
      • 5.2 懒汉模式
      • 5.2 懒汉模式-线程安全(改进)

博客结尾有此篇博客的全部代码!!!

一、引言

假设这里有一个ATM机,然后有人排队取钱,有人排队存钱
在这里插入图片描述
ATM机时进去一个人,门自动关门上锁。
现实生活中,假设第一个人进去取钱,但是恰好此时ATM机里面没有钱,第一个人就出来,刚出来他又觉得ATM机里面有钱了(有押运车来往里放 钱),又进去了,他这样来回反复横跳,一直占着ATM机,不让第二个和第三个人使用!

在操作系统中,这种情况是经常发生的,因为资源的调度是随机的。假设这里有多个线程,系统一直调用某一个线程,让其他线程一直处于阻塞等待,这种情况就叫做线程饿死(线程饥饿)

那么怎么解决这种问题呢?这里就引出了wait()方法!!!

一、wait()方法

  • wait() 方法用于使当前线程等待(挂起)(释放当前锁),让其他线程可以使用这把锁。
    public static void main(String[] args) {Object lock = new Object();Thread t1 = new Thread(() -> {synchronized (lock) {try {System.out.println("wait 之前");lock.wait();System.out.println("wait 之后");} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.start();}

由于这段代码在执行wait()方法之后就一直等待下去,这里肯定不可能让这段代码一直等待下去。所以就引入一个新的方法唤醒wait()方法------notify()方法。

wait()方法需要注意的:

  1. 必须搭配synchronized()使用,脱离synchronized()就会抛出异常
  2. 其他线程调⽤该等待线程的 interrupted ⽅法, 导致 wait 抛出 InterruptedException 异常
  3. wait()方法也有等待超时

二、notify()方法

这个方法是为了唤醒wait()方法,防止wait()方法一直等待下去!
• ⽅法notify()也要在同步⽅法或同步块中调⽤,该⽅法是⽤来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
• 如果有多个线程等待,则有线程调度器随机挑选出⼀个呈 wait 状态的线程。(并没有 “先来后到”)
• 在notify()⽅法后,当前线程不会⻢上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

public class Demo2 {public static void main(String[] args) {Object lock = new Object();Thread t1 = new Thread(() -> {synchronized (lock) {try {System.out.println("wait 之前");lock.wait();System.out.println("wait 之后");} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2 = new Thread(() -> {synchronized (lock) {lock.notify();System.out.println("唤醒wait()方法");}});t1.start();t2.start();}
}

如果这里有多个wait()方法,只有一个notify()方法,这个唤醒是随机的!!!

三、notifyAll()方法

notify⽅法只是唤醒某⼀个等待线程. 使⽤notifyAll⽅法可以⼀次唤醒所有的等待线程.

    public static void main(String[] args) {Object lock1 = new Object();Object lock2 = new Object();Thread t3 = new Thread(() -> {synchronized (lock1) {try {System.out.println("t3 wait()方法之前");lock1.wait();System.out.println("t3 wait()方法之后");} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t1 = new Thread(() -> {synchronized (lock1) {try {System.out.println("t1 wait()方法之前");lock1.wait();System.out.println("t1 wait()方法之后");} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2 = new Thread(() -> {synchronized (lock1) {lock1.notifyAll();System.out.println("唤醒wait()方法");}});t3.start();t1.start();t2.start();}
}

wait()、notify()、notifuAll()三种方法都是Object类中的方法!!!

四、wait()和sleep()对比

相同:

  • 都可以让线程放弃一段时间。

不同:

wait:

  • 是Object类中的方法
  • 需要搭配synchronized使用
  • 用于线程间的协作
  • 释放锁,允许其他线程运行
  • 需要在同步块中调用
  • 可以通过 notify() 或超时唤醒

sleep:

  • 是Thread的静态方法
  • 用于简单的延时操作
  • 不释放锁
  • 可以在任何地方调用
  • 只能通过睡眠时间结束或中断唤醒

五、单例模式

设计模式(Design Patterns)是软件工程中用于解决常见问题的可复用的解决方案。它们是经过验证的最佳实践,能够帮助开发者设计出更灵活、可维护和可扩展的代码。

单例模式能保证某个类在程序中只存在唯⼀⼀份实例, ⽽不会创建多个实例。
Thread t1=new Thread();t1就是创建的实例。

单例模式具体的实现方式有很多,最常见的是“饿汉”和“懒汉”两种。

5.1 饿汉模式

类加载的同时,创建实例

class MyDesign{private static MyDesign obj = new MyDesign();private MyDesign(){}public static MyDesign getInstance(){return obj;}
}

5.2 懒汉模式

类加载的时候不创建实例. 第⼀次使⽤的时候才创建实例.

class MyDesignF{private static MyDesignF obj = null;private MyDesignF(){}public static MyDesignF getInstance(){if(obj == null){obj = new MyDesignF();}return obj;}
}

饿汉模式不会出现线程安全问题;懒汉模式会出现线程安全问题!

饿汉模式:没有修改操作,所以不会出现线程安全问题。
懒汉模式:有修改操作,所以线程不安全。

在这里插入图片描述

5.2 懒汉模式-线程安全(改进)

  • 加synchronized
class MyDesignF{private static MyDesignF obj = null;private MyDesignF(){}public  static MyDesignF getInstance(){synchronized (MyDesignF.class){if(obj == null){obj = new MyDesignF();}}return obj;}
}
  • 双重if判断,降低锁竞争的频率
class MyDesignF{private static MyDesignF obj = null;private MyDesignF(){}public  static MyDesignF getInstance(){if(obj == null){synchronized (MyDesignF.class){if(obj == null){obj = new MyDesignF();}}}return obj;}
}
  • 给obj加上volatile
class MyDesignF{private volatile static MyDesignF obj = null;private MyDesignF(){}public  static MyDesignF getInstance(){if(obj == null){synchronized (MyDesignF.class){if(obj == null){obj = new MyDesignF();}}}return obj;}
}

volatile关键字作用:(防止指令重排序
在懒汉模式中,obj = new MyDesignF();也可以分为三步:

  • 分配内存空间。----1
  • 调用构造函数初始化对象。----2
  • 将内存地址赋值给 obj 变量。----3

正常情况下是1-》2-》3,但如果发生指令重排序就会出现1-》3-》2,先将内存地址赋值给obj,但还没有进行初始化对象,此时如果另一个线程访问obj,还未完全初始化的对象,那么此时就出现错误!!!

此篇博客的全部代码!!!

关键字:商务网站开发_博达网站建设教程_百度指数十年_长尾关键词挖掘词工具

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: