当前位置: 首页 > wzjs >正文

网站开发u盘128够吗网络推广公司北京

网站开发u盘128够吗,网络推广公司北京,网站开发总结 优帮云,社会化网络营销是什么目录 前言 1.wati() 和 notify() wait() 和 notify() 的产生原因 如何使用wait()和notify()? 案例一:单例模式 饿汉式写法: 懒汉式写法 对于它的优化 再次优化 结尾 前言 如何简单的去使用jconsloe 查看线程 (多线程编程篇1)_eclipse查看线程-CSDN博客 浅谈Thread类…

目录

前言

1.wati() 和 notify()

wait() 和 notify() 的产生原因

如何使用wait()和notify()?

 案例一:单例模式 

 饿汉式写法:

 懒汉式写法 

对于它的优化

 再次优化

结尾 

前言

如何简单的去使用jconsloe 查看线程 (多线程编程篇1)_eclipse查看线程-CSDN博客

浅谈Thread类及常见方法与线程的状态(多线程编程篇2)_thread.join() 和thread.get()-CSDN博客

这是系列的第三篇博客,这篇博客笔者想结合自己的学习经历,分享几个多线程编程的简单案例,帮助读者们更快的理解多线程编程,也非常感激能耐心阅读本系列博客的读者们!

本篇博客的内容如下,您可以通过目录导航直接传送过去

1.介绍wait()和notify()这两个方法

2.介绍单例模式

废话不多说,让我们开始吧,希望我们在知识的道路上越走越远!

博客中出现的参考图都是笔者手画或者截图的的

代码示例也是笔者手敲的!

影响虽小,但请勿抄袭

1.wati() 和 notify()

wait() 和 notify() 的产生原因

在多线程编程中,多个线程同时读写共享资源非常常见。假设两个线程要交替操作一个数据,比如:

  • 线程A:负责生产数据;

  • 线程B:负责消费数据。

如果没有协调机制,线程A和线程B的执行顺序完全由CPU调度,极有可能出现这种情况:

  • 线程B执行时,发现A还没生产好;

  • 线程A刚生产好,B却还没来消费。

这样会出现资源使用错误,甚至死循环。

所以,Java提供了 wait()notify(),解决线程之间通信的问题,帮助程序做到:

 一个线程在条件不满足时,自动等待。
 另一个线程操作完后,主动唤醒等待的线程。

这种机制,叫做等待-通知机制"。

具体来说:

wait()方法:让指定的程序进入阻塞状态

wait 结束等待的条件 :
1.其他线程调用该对象的 notify 方法 .
2.wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本 , 来指定等待时间 ).
3.其他线程调用该等待线程的 interrupted 方法 , 导致 wait 抛出 InterruptedException 异常 .

notify()方法:唤醒对应的处在阻塞状态的线程.

举个生活中的例子:

假设你去银行取号排队:

  • 你取号后坐在椅子上等待(相当于调用 wait() 进入等待状态)。

  • 银行的叫号系统喊你的号码时,你再去窗口办理业务(相当于 notify() 唤醒你)。

如果没有这个等待机制,你可能得不停地站在窗口问“轮到我了吗?什么时候才能到我啊?前面的人能不能tm快点啊!”(浪费CPU资源)

有了 wait()notify(),就能让线程“高效地等待”而不是死循环轮询

如何使用wait()和notify()?

OK了解了他们的概念和作用,接下来,笔者将介绍如何使用wait()和notify()

首先,读者们需要了解一些前置知识

第一:根据源码文档,wait() 方法在调用时,必须处理 InterruptedException
因此使用时要么用 try-catch 捕获,要么在方法上声明 throws,否则代码无法通过编译。

第二:wait() 和 notify() 方法并不是定义在 Thread 类中,而是属于 Object 类的方法。
所以在实际使用中,我们通常需要先创建一个 Object 对象,通过这个对象来调用 wait()和 notify(),并且配合 synchronized 关键字一起使用,确保线程安全。

请看一组示例代码:

public class Demo
{public static void main(String[] args) {Object  ob = new Object();Object  lock = new Object();Thread thread1 = new Thread(() ->{synchronized (ob){System.out.println("wait 之前");try {ob.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("进入了");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("wait 之后");});
wait 做的事情:
使当前执行代码的线程进行等待. (把线程放到等待队列中)
释放当前的锁
满足一定条件时被唤醒, 重新尝试获取这个锁.Thread thread2 = new Thread(()->{try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (ob){System.out.println("通知了");ob.notify();}});thread1.start();thread2.start();}
}

在使用 wait()notify() 这两个方法时,有一个非常重要的前提条件:

调用它们时,必须先持有调用对像的锁,而且必须时同一个对像,否则会抛出异常

我们一定要保证,哪个对像调用了wati(),哪个对像就要调用notify(),或者也要设置好阻塞时间. 

synchronized (ob) {ob.wait();  //  正确,线程1的锁对象是 ob
}synchronized (lock) {ob.notify();  //  错误,线程2的锁对象是 lock,调用 notify 却针对 ob
}
错误写法
synchronized (ob) {ob.wait();  //  正确,线程1的锁对象是 ob
}synchronized (ob) {ob.notify();  
正确写法


 案例一:单例模式 

 单例模式是一种设计模式

它保证了一个类在内存中永远只会有一个对象实例.并且提供全局访问点。

举个例子:

假设你要开发一个系统中的配置文件读取器,配置文件只需要加载一次,所有模块都要读取相同的配置信息。如果每次调用都重新 new 一个对象,不仅浪费内存,而且可能导致配置不一致。
通过单例模式,你可以保证这个读取器在整个程序运行期间只创建一次,并且全局唯一! 

又或者 比如 JDBC 中的 DataSource 实例就只需要一个!!!

 单例模式也有两种写法 : 

1.懒汉式: 只要在需要被实例化的时候,才会被实例化.

2.饿汉式:顾名思义,在类内部创建唯一实例,并且用 private static final 修饰,保证类一旦被加载了,就开始实例化了

 饿汉式写法:

public class Singleton {// 饿汉单例,类一旦被加载,就开始实例化了// 1️⃣ 在类内部创建唯一实例,并用 `private static final` 修饰private static final Singleton demo = new Singleton();// 2️⃣ 私有构造方法,防止外部创建实例// 静态代码块private Singleton() {System.out.println("Singleton 实例被创建");}// 3️⃣ 提供公共方法获取实例public static Singleton getInstance() {return demo;}
}

在饿汉式单例中,我们会直接在类内部创建好对象实例,当类加载进内存时,实例就已经完成了初始化。

这是因为我们使用了 static 关键字来修饰这个实例,static 属于类本身,随着类的加载而初始化。
所以,只要 JVM 加载这个类,单例对象就会被创建,并且保证全局只有一个。

在 Java 中,static 修饰的属性或方法属于类本身,而不是某个具体对象。
类被加载到内存时,所有 static 修饰的成员(属性、方法、代码块)会随类一起初始化,而且只会初始化一次。

也就是说:

  • 类加载时,static 属性会被分配内存并初始化。

  • static 方法属于类本身,不依赖对象,可以通过类名.方法名()调用。

我们简单测试一下:

class  MyTest
{public static void main(String[] args) {Singleton s1 =  Singleton.getInstance();}
}

调用  Singleton.getInstance()的时候,类被加载,demo被初始化,并且  Singleton() 构造方法被执行,打印"Singleton 实例被创建".

 
懒汉式写法 

类加载的时候不创建实例 . 第一次使用的时候才创建实例 . 我们依据这个思路,写出来懒汉式单例
public class SingletonLazy {// 1️⃣ 声明一个静态变量用来存储实例private static  SingletonLazy instance;// 2️⃣ 私有构造方法,防止外部创建实例private SingletonLazy() {System.out.println("SingletonLazy 构造方法执行:对象创建成功!");}// 3️⃣ 提供公共的静态方法来获取实例,第一次调用时实例化public static SingletonLazy getInstance() {instance = new SingletonLazy();return instance;}

为了测试懒汉和饿汉的不同,我们再写两个辅助的静态方法测试:

public class SingletonLazy {// 1️⃣ 声明一个静态变量用来存储实例private static  SingletonLazy instance;// 2️⃣ 私有构造方法,防止外部创建实例private SingletonLazy() {System.out.println("SingletonLazy 构造方法执行:对象创建成功!");}// 3️⃣ 提供公共的静态方法来获取实例,第一次调用时实例化public static SingletonLazy getInstance() {instance = new SingletonLazy();return instance;}static {System.out.println("SingletonLazy 类已加载!");}public static void printf() {System.out.println("调用了静态方法 printf()");}}

测试一下:

class Test {public static void main(String[] args) {// 不调用 getInstance 只调用静态方法SingletonLazy.printf();  // 会触发类加载,但不会创建对象!System.out.println("---------------");// 真正调用 getInstance,才会创建对象SingletonLazy s1 = SingletonLazy.getInstance();SingletonLazy s2 = SingletonLazy.getInstance();}
}

结果如下:

调用静态方法后,类会被加载,但此时并不会执行构造方法,也就是说对象还没有被创建。只有当调用 getInstance()  方法时,程序才会真正实例化对象,执行构造方法,完成对象的创建!

我们还可以做一点优化,我们都知道这是单例模式, 只允许有一个对象实例,那么,只有第一次访问时才需要被创建,后续就不用再次创建了,因此可以写成:

public class SingletonLazy {// 1️⃣ 声明一个静态变量用来存储实例private static volatile SingletonLazy instance;// 2️⃣ 私有构造方法,防止外部创建实例private SingletonLazy() {System.out.println("SingletonLazy 构造方法执行:对象创建成功!");}// 3️⃣ 提供公共的静态方法来获取实例,第一次调用时实例化public static SingletonLazy getInstance() {if(instance == null){instance = new SingletonLazy();           }return instance;}
}

 如果在单线程编程下,这样就挑不出毛病了!

对于它的优化

但是,假设在多线程环境下,有复数个线程同时调用  getInstance() ,那么就会创建出多个实例

举一个具体的例子

一旦程序进入多线程环境,比如存在A、B、C 三个线程,它们几乎在同一时刻调用 getInstance()方法

在这一瞬间,instance 的确是 null,三个线程会同时通过 if 判断,然后同时执行 new SingletonLazy(),最终结果就是:

创建了多个实例,破坏了单例模式!!!

因此,我们希望判断是否为空,以及创建实例,这两个动作"原子化"——即不会也不能被打断

怎么办?聪明的你肯定想到了,加锁!

    public static SingletonLazy getInstance() {     synchronized (SingletonLazy.class) {if (instance == null) {instance = new SingletonLazy();}}return instance;}

加完锁以后,刚刚的情况就会变为:

1.假设程序运行在多线程环境下,A、B、C 三个线程几乎在同一时间,调用了 getInstance() 方法。

2.在这一瞬间,instance 的确是 null,于是三个人一起冲进来,准备创建对象。但是!因为这里加了 synchronized,所以三个线程必须抢锁,只有一个幸运儿能抢到,比如A线程。

3.然后A线程释放锁,B、C线程后面排队进来,发现 instance 已经不再是 null,所以它们就啥也不干,直接返回已有的实例。

4.这样一来,就保证了全局唯一实例,不会被多线程同时创建多个,单例模式真正实现了!

 再次优化

不过啊,虽然上面这种“方法加锁”确实解决了多线程下的安全问题——只要一个线程进来了,其他线程就乖乖排队,等着用同一个实例,表面上看没毛病。

但是!问题又来了:

每次调用 getInstance(),都要加锁。
不管 instance 有没有被创建,线程都得卡着 synchronized 排队。

想一想——如果我已经拿到实例了,后面无数次调用其实都只是想用一下这个对象,根本不需要再创建,可还是得老老实实抢锁,这效率能不低吗? 毕竟,加锁的开销也不小了.

所以,聪明的程序员又想了个办法,叫:

双重检查锁(Double-Check Locking),简称 DCL。

核心思路就一句话:

先检查,不满足再加锁,锁住后再检查,确认安全后再创建。

也就是说,外面先检查一次,里面再检查一次,这样只有在 instance 真正等于 null 的时候,才会走到创建对象的逻辑,其他时候,直接跳过锁,快速返回。

public class SingletonLazy {// 加上 volatile,防止指令重排序private static volatile SingletonLazy instance;private SingletonLazy() {System.out.println("SingletonLazy 构造方法执行:对象创建成功!");}public static SingletonLazy getInstance() {if (instance == null) {  // 第一次检查synchronized (SingletonLazy.class) {if (instance == null) {  // 第二次检查instance = new SingletonLazy();}}}return instance;}
}

而且还有个小细节,volatile 关键字也别忘了加上!

因为 Java 内存模型中,new 操作可能会被“重排序”

那么,还是刚刚ABC三线程竞争的例子:

1.

A、B、C 三个线程同时调用 getInstance(),一起执行第一次 if (instance == null)

2. 假设 instance 真的为 null,于是三个线程都准备往下走。

3.

A、B、C 到达 synchronized 这里,开始抢锁。假设A赢了,进入同步代码块。

A 再次执行第二次 if (instance == null),发现确实为空,于是创建 new SingletonLazy()
A 创建完成后,释放锁。

4.

B、C 排队进来,再次检查 if (instance == null),发现已经不为空了,直接跳过创建,返回已存在的实例。 

这样对比普通加锁的好处是,实例化以后,先判断一下是否是空,而不是多个线程直接去竞争锁导致资源浪费

总结一句话:
DCL的好处就是,实例化之后,线程们先看一眼:
"对象在不在?"
在,就立刻用!
不在,才排队抢锁。

相比“每次都抢锁”的方式,DCL大幅减少了资源浪费,尤其适合多线程访问频繁的场景。

完整代码:

public class SingletonLazy {// 1️⃣ 声明一个静态变量用来存储实例private static volatile SingletonLazy instance;// 2️⃣ 私有构造方法,防止外部创建实例private SingletonLazy() {System.out.println("SingletonLazy 构造方法执行:对象创建成功!");}// 3️⃣ 提供公共的静态方法来获取实例,第一次调用时实例化public static SingletonLazy getInstance() {if(instance == null){synchronized (SingletonLazy.class) {if (instance == null) {instance = new SingletonLazy();}}}return instance;}
// 外层 if 的作用:
// 避免已经实例化对象的情况下,仍然加锁。因为加锁是一种消耗性能的操作,
// 所以外层先判断,能直接返回就直接返回,提高效率。// 内层 if 的作用:
// 防止多个线程在 instance == null 的情况下,同时进入同步代码块,
// 抢锁后,重复创建实例。内层 if 可以保证只有第一个抢到锁的线程会创建实例。// 假设 instance 初始为 null,两个线程 A 和 B 几乎同时调用 getInstance():
// 【第一阶段:外层 if 判断(无锁)】
// - 线程A发现 instance == null,进入同步块等待抢锁。
// - 线程B也发现 instance == null,也准备进入同步块等待抢锁。// 【第二阶段:尝试获取锁】
// - 线程A抢到 synchronized(SingletonLazy.class) 的锁,进入同步块,开始执行内层代码。
// - 线程B未抢到锁,必须等待线程A释放锁,挂起等待。// 【第三阶段:内层 if 判断】
// - 线程A在内层再次检查 instance 是否为 null,
//   如果确实是 null,就创建 SingletonLazy 实例。
// - 线程A释放锁,线程B接着抢到锁。// 【第四阶段:线程B再次检查】
// - 线程B进入同步块,内层 if 判断时,发现 instance 已经不是 null,
//   所以不会再创建新对象,直接返回已存在的实例。// 【总结】
// 这样写的双重检查机制,既保证了线程安全,
// 又避免每次都去加锁,提升了性能!// 辅助方法,观察类是否加载static {System.out.println("SingletonLazy 类已加载!");}public static void printf() {System.out.println("调用了静态方法 printf()");}
}class Test {public static void main(String[] args) {// 不调用 getInstance 只调用静态方法SingletonLazy.printf();  // 会触发类加载,但不会创建对象!System.out.println("---------------");// 真正调用 getInstance,才会创建对象SingletonLazy s1 = SingletonLazy.getInstance();SingletonLazy s2 = SingletonLazy.getInstance();}
}

结尾 

写到这里的时候,大约花费了笔者120分钟,写了8145个字

本来笔者想接着介绍阻塞队列的,看来只能留到下次了!

笔者的风格是每一步都会写的很详细,因为笔者觉得自己天赋不佳,需要在学会的时候记录的越详细越好,方便读者查阅和调用

希望笔者如此之高质量的博客能帮助到你我他!

http://www.dtcms.com/wzjs/4223.html

相关文章:

  • 昆明网站建设制作在线教育
  • 长春市建委官网360优化大师历史版本
  • wordpress程序 耗内存宁波免费seo排名优化
  • 成都设计网站快抖霸屏乐云seo
  • 如何修改网站备案的域名成人短期技能培训
  • 数据网站怎么做的百度百度推广
  • 做网站时背景图片浮动重庆seo论坛
  • 建材网站建设方案网络推广是什么
  • 东莞宣布优化防疫措施关键词seo服务
  • 个人网站做企业备案搜索引擎有哪些
  • 网页设计淘宝首页html代码seo公司推荐推广平台
  • 网站建设和管理工作冯耀宗seo教程
  • 一流的网站建设与优化网络营销的主要方式
  • 哪个设计网站做兼职好网站优化推广教程
  • 亲子游网站怎么做免费域名申请的方法
  • 南充免费推广网站自媒体人15种赚钱方法
  • 电商网站建设需求分析 实例题深圳网站设计知名乐云seo
  • 惠州做棋牌网站建设找哪家效益快全媒体广告代理
  • 在线视频网站怎么做seo国际时事新闻
  • 怎么快速提高网站权重知了seo
  • 无锡网站建设开发游戏行业seo整站优化
  • 公司网站建设内容建议枸橼酸西地那非片的作用及功效
  • 杭州网站建设网络公司今日的最新消息
  • php中网站搜索功能实现信息流推广渠道有哪些
  • 营销型网站建设策划书怎么写个人永久免费自助建站
  • 郑州高端网站建设怎么样代运营电商公司
  • 沈阳网站建设技术公司线上推广是做什么的
  • 苹果cms如何做网站重庆百度推广开户
  • 营销网站的策划方案怎么做百度竞价排名的优缺点
  • 重庆网站建设加q.479185700公司官网搭建