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

做网站一年百度应用app

做网站一年,百度应用app,哪些网站可以做代理,怎么做一考试网站文章目录 一、线程间的通信(1)为什么要处理线程间的通信(2)等待唤醒机制 二、案例(1)案例1、创建线程2、解决线程安全问题3、等待4、唤醒5、同步监视器 (2)调用wait和notify需注意的…

文章目录

  • 一、线程间的通信
    • (1)为什么要处理线程间的通信
    • (2)等待唤醒机制
  • 二、案例
    • (1)案例
      • 1、创建线程
      • 2、解决线程安全问题
      • 3、等待
      • 4、唤醒
      • 5、同步监视器
    • (2)调用wait和notify需注意的细节
  • 三、wait与sleep的区别

一、线程间的通信

(1)为什么要处理线程间的通信

当我们需要多个线程共同完成一件任务,并且我们希望他们有规律的执行,那么多线程之间需要一些通信机制,可以协调它们的工作,以此实现多线程共同操作一份数据。(在同步的基础之上解决通信的问题)

比如:线程A用来生产包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,此时B线程必须等到A线程完成后才能执行,那么线程A与线程B之间就需要线程通信,即—— 等待唤醒机制。

(2)等待唤醒机制

这是多个线程间的一种协作机制

谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制

在一个线程满足某个条件时,就进入等待状态(wait() / wait(time)), 等待其他线程执行完他们的指定代码过后再将其唤醒(notify());

或可以指定wait的时间,等时间到了自动唤醒;

在有多个线程进行等待时,如果需要,可以使用 notifyAll()来唤醒所有的等待线程。wait/notify 就是线程间的一种协作机制。

  1. wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态是 WAITING 或 TIMED_WAITING。它还要等着别的线程执行一个特别的动作,也即“通知(notify)”或者等待时间到,在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中。
  2. notify:则选取所通知对象的 wait set 中的一个线程释放。
  3. notifyAll:则释放所通知对象的 wait set 上的全部线程。

🗳️注意:

被通知的线程被唤醒后也不一定能立即恢复执行,因为它当初中断的地方是在同步块内,而此刻它已经不持有锁,所以它需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait 方法之后的地方恢复执行。

总结如下:

  • 如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE(可运行) 状态;
  • 否则,线程就从 WAITING 状态又变成 BLOCKED(等待锁) 状态

二、案例

(1)案例

🌋案例描述:

使用两个线程打印 1-100。线程1, 线程2 交替打印。

🍰分析

1、创建线程

这里使用实现的方式创建线程。

class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {}
}

run方法里面写上逻辑代码:

class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){if(number<=100){System.out.println(Thread.currentThread().getName()+":"+number);number++;}else{break;}}}
}

main方法中创建两个线程,如下:

public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}

关于number的问题,需要考虑同步

if中加一个sleep,将问题放大。

目前的代码如下:

public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;}else{break;}}}
}

输出:

image.png

可以看到打印出了错误信息。


2、解决线程安全问题

现在我们使用同步代码块来解决线程安全问题。

将操作number的代码用synchronized包裹起来,就是下面蓝色部分:

image.png

synchronized包裹的时候,不能包裹少了,那样会有安全问题。

若是包裹多了,串行的场景就会更多,导致效率变低。

所以,操作共享数据的代码,不能包裹多,也不能少。

🌱代码

package yuyi04.Communication;/*** ClassName: PrintNumberTest* Package: yuyi04.Communication* Description:*  使用两个线程打印 1-100。线程1, 线程2 交替打印。* @Author 雨翼轻尘* @Create 2024/2/2 0002 14:57*/
public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){synchronized (this) {   //当前this表示PrintNumber的实例,即p,是唯一的if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;}else{break;}}}}
}

🍺输出

image.png

可以看到现在的线程是安全的。


3、等待

紧接着需要考虑下一个问题,需要将两个线程交替打印

🎲如何实现交替?

比如线程1进入同步代码块,然后打印结束,出了同步代码块。

此时线程1需要进入阻塞状态,让线程2进入同步代码块输出执行,才能保证与线程1交替执行。

如何让线程1处于阻塞,这里需要使用一个方法wait(),让它处于等待状态。如下:

image.png

线程一旦执行wait()方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用

wait()方法有一个异常需要处理一下:

image.png

注意,sleep()不会释放同步监视器,这一点需要注意。

有时候面试会问,wait()sleep()有什么区别?

这就是其中一个区别,sleep()不会释放对同步监视器的调用,而wait()会释放对同步监视器的调用。

🌱代码

public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){synchronized (this) {   //当前this表示PrintNumber的实例,即p,是唯一的if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;try {wait(); //线程一旦执行此方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用} catch (InterruptedException e) {e.printStackTrace();}}else{break;}}}}
}

🍺输出

image.png

☕注意

一旦线程1进入同步代码块执行到wait(),就会释放对同步监视器的调用,然后开始等待操作。

线程2就可以拿着同步监视器进入同步代码块了,当线程2执行到wait(),它也开始等待。

所以两个线程都处于等待状态,只能输出两个数字,然后进入了阻塞状态


4、唤醒

🎲如何不一直等待下去呢?

Ctrl+P可以看到wait()方法还有带参的,可以设置等待时间,就是达到时间自动醒来。如下:

image.png

现在我们不使用这个了,因为想让它们交互输出,可以考虑唤醒线程。

线程1进入同步代码块执行到wait(),然后释放同步监视器,线程2进入同步代码块。

所以我们需要在线程2wait()之前把线程1唤醒

可以在这里写上notify(),如下:

image.png

🍰分析一下现在的情况:

线程1进入同步代码块,碰到了notify(),发现没有可以唤醒的线程,就继续往后执行。

然后线程1打印了“1”,接下来执行到wait(),开始等待,并且释放同步监视器。

线程2拿到锁,进入同步代码块,碰到了notify(),发现线程1在等待,就将线程1叫醒,虽然叫醒了,但是没有用,因为已经没有同步资源了。

线程2就拿着锁继续执行,即使sleep也不影响自动睡醒之后继续往后执行(sleep不会导致锁被释放),然后输出“2”。

线程2执行到wait(),就开始等待了,同时也释放同步监视器。

此时线程1是醒着的状态,从被wait()的地方继续往后执行,后边要是有代码的话还需要继续执行,然后拿着锁再次进入同步代码块,然后碰到notify(),将线程2叫醒。

🌱代码

package yuyi04.Communication;/*** ClassName: PrintNumberTest* Package: yuyi04.Communication* Description:*  使用两个线程打印 1-100。线程1, 线程2 交替打印。* @Author 雨翼轻尘* @Create 2024/2/2 0002 14:57*/
public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;@Overridepublic void run() {//打印数据while(true){synchronized (this) {   //当前this表示PrintNumber的实例,即p,是唯一的notify();if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;try {wait(); //线程一旦执行此方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用} catch (InterruptedException e) {e.printStackTrace();}}else{break;}}}}
}

🍺输出(部分)

image.png

现在看到的就是交互的场景。


5、同步监视器

🗳️关于同步监视器

这里其实省略了this,如下:

image.png

wait同理:

notify();   //this.notify();
wait();		//this.wait();

凡是在方法当中,没有写是谁调用的,如果是非静态方法,那就少了this。

若是静态方法,那就是当前类。

这里的this必须是一样的吗?如下:

image.png

我们先来自己定义一个同步监视器,然后将obj放入:

image.png

🌱代码

public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;Object obj=new Object();@Overridepublic void run() {//打印数据while(true){synchronized (obj) {   //obj是唯一的,线程安全this.notify();   //notify();if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;try {wait(); //线程一旦执行此方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用} catch (InterruptedException e) {e.printStackTrace();}}else{break;}}}}
}

🍺输出

image.png

会报一个异常IllegalMonitorStateException,这表示当前使用的同步监视器(即obj)和notify()wait()方法的调用者不一致。

所以,它们的调用者,必须是同步监视器。(这里也可以看出,notifywait方法必须要在同步代码块或同步方法中使用,只有这两个结构中才存在同步监视器,Lock里面没有同步监视器)


🚗处理

既然现在的同步监视器是obj,那么就用obj去调用notifywait方法即可。

如下:

image.png

🌱代码

package yuyi04.Communication;/*** ClassName: PrintNumberTest* Package: yuyi04.Communication* Description:*  使用两个线程打印 1-100。线程1, 线程2 交替打印。* @Author 雨翼轻尘* @Create 2024/2/2 0002 14:57*/
public class PrintNumberTest {public static void main(String[] args) {//创建PrintNumber类的实例PrintNumber p=new PrintNumber();Thread t1=new Thread(p,"线程1");Thread t2=new Thread(p,"线程2");t1.start();t2.start();}
}class PrintNumber implements Runnable{//共享100private int number=1;Object obj=new Object();@Overridepublic void run() {//打印数据while(true){synchronized (obj) {   //obj是唯一的,线程安全obj.notify();   //notify();if(number<=100){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+number);number++;try {obj.wait(); //线程一旦执行此方法,就进入等待状态(阻塞),同时会释放对同步监视器的调用} catch (InterruptedException e) {e.printStackTrace();}}else{break;}}}}
}

🍺输出(部分)

image.png

notifywait方法的调用者必须是“同步监视器”。

(2)调用wait和notify需注意的细节

上述案例涉及到三个方法的使用:

  • wait():线程一旦执行此方法,就进入等待状态。同时,会释放对同步监视器的调用
  • notify():一旦执行此方法,就会唤醒被wait()的线程中优先级最高的那一个线程。(如果被wait()的多个线程的优先级相同,则随机唤醒一个)。被唤醒的线程从当初被wait的位置继续执行。
  • notifyAll():一旦执行此方法,就会唤醒所有被wait的线程

🗳️注意点

  • 此三个方法的使用必须是在同步代码块或同步方法(即synchronized结构)。(超纲:Lock需要配合Condition实现线程间的通信,方式更加灵活)
  • 此三个方法的调用者,必须是同步监视器。否则,会报IllegalMonitorStateException异常。
  • 此三个方法声明在Object类中。(当初说同步监视器的时候,说到“任何一个对象都可以来充当同步监视器”,那么就意味着任何一个对象都应该有能力去调用这几个方法,这几个方法必定是定义在Object类里面的)

image.png


☕调用waitnotify需注意的细节总结

1、wait方法与notify方法必须要由同一个锁对象调用

因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。

2、wait方法与notify方法是属于Object类的方法的。

因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。

3、wait方法与notify方法必须要在同步代码块或者是同步函数中使用。

因为:必须要通过锁对象调用这2个方法。否则会报java.lang.IllegalMonitorStateException异常。

三、wait与sleep的区别

🎲wait()sleep()的区别?(常见面试题)

相同点:一旦执行,都会使得当前线程结束执行状态,进入阻塞状态

不同点

  • 声明的位置(定义方法所属的类)
    • wait():声明在Object类中。
    • sleep():声明在Thread类中,静态的。
  • 使用的场景不同(使用范围不同)
    • wait()只能使用在同步代码块或同步方法中
    • sleep()可以在任何需要使用的场景
  • 都在同步结构(同步代码块或同步方法)中使用的时候,是否释放同步监视器的操作不同
    • wait():一旦执行,会释放同步监视器
    • sleep():一旦执行,不会释放同步监视器
  • 结束阻塞的方式(结束等待的方式不同)
    • wait()到达指定时间自动结束阻塞无限等待直到被notify/notifyAll唤醒,结束阻塞。
    • sleep()到达指定时间自动结束阻塞
http://www.dinnco.com/news/4730.html

相关文章:

  • 怎样做百度推广网站天天广告联盟
  • 研究生做网站开发如何免费自己创建网站
  • 石家庄平台公司seo快速排名外包
  • 南山区网站建设公司新闻头条最新
  • 企业网站全屏轮播怎么做友情链接例子
  • 台山网站建设关键词竞价排名名词解释
  • 如何查网站的外链公众号营销
  • 网站速度黄冈网站搭建推荐
  • 网站建设的售后广西百度seo
  • 自动做任务赚钱的网站电商培训心得体会
  • 网站建设实训指导书深圳专门做seo的公司
  • 成品网站设计网站常州百度关键词优化
  • 怎么做网站dreamwave吴中seo页面优化推广
  • 邢台网站建设基本流程湖南正规关键词优化报价
  • 装修公司谁做网站全网模板建站系统
  • 哪里有免费的网站模板北京cms建站模板
  • 阿里巴巴的电子商务网站建设网络运营商
  • 网站怎么做关键词优化seo的培训班
  • 电子商务网站建设技巧郑州seo技术顾问
  • 燕郊做网站的公司app代理推广合作50元
  • 网站空间哪家好网络推广有哪些常见的推广方法
  • 网站建设成本费用dy刷粉网站推广马上刷
  • 网站开发的核心技术google推广seo
  • 精品课程建设网站清单360推广
  • 强生公司营销网站为什么要这样做项目优化seo
  • 嘉兴做网站公司哪家好网站seo方案模板
  • 青岛网站建设seo优化网站宣传的方法有哪些
  • 社交平台网站建设预算周口网络推广公司
  • 网站建设合同有效期百度入口官网
  • 加强医院微信和网站建设百度提交工具