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

无锡网站关键词优化郑州logo设计公司

无锡网站关键词优化,郑州logo设计公司,龙华附近网站建设公司,免费云主机哪个好专栏:JavaEE初阶起飞计划 个人主页:手握风云 目录 一、volatile关键字 1.1. 原理 1.2. Java memory model(Java内存模型) 1.3. volatile与synchronized的区别 二、wait和notify 2.1. wait()方法 2.2. notify()方法 2.3. notifyAll()方法 一、vol…

专栏:JavaEE初阶起飞计划

个人主页:手握风云

目录

一、volatile关键字

1.1. 原理

1.2. Java memory model(Java内存模型)

1.3. volatile与synchronized的区别

二、wait和notify

2.1. wait()方法

2.2. notify()方法

2.3. notifyAll()方法


一、volatile关键字

1.1. 原理

        当给变量添加了volatile关键字后,当编译器看到volatile的时候,就会提醒JVM运行的时候不进行上述的优化。具体来说,在读写volatile变量的前后指令添加“内存屏障相关的指令”。

1.2. Java memory model(Java内存模型)

        首先一个Java进程,会有一个“主内存”存储空间,每个Java线程又会有自己的“工作内存”存储空间。形如下面的代码,t1进行flag变量的判定,就会把flag值从主内存先读取到工作内存,用工内存中的值进行判定。同时t2对flag进行修改,修改的则是主内存的值,主内存中的值不会影响到工作内存中的值。这里的工作内存相当于是打了个比方,本质上是CPU的寄存器和CPU的缓存构成的统称。

import java.util.Scanner;public class Demo1 {private static int flag = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag == 0) {}System.out.println("t1线程结束");});Thread t2 = new Thread(() -> {Scanner in = new Scanner(System.in);System.out.println("请输入flag的值:");flag = in.nextInt();System.out.println("t2线程结束");});t1.start();t2.start();t1.join();t2.join();}
}

        其实,存储数据,不光是只有内存,外存(硬盘)、CPU寄存器、CPU上的缓存。

        上图中的缓存也是CPU上存储数据的单元。寄存器能存数据,但是空间小;内存能存数据,空间大,但是速度慢。为了能够更好地协调寄存器和内存的数据同步,因此现代CPU都引入了缓存。CPU的缓存,空间比寄存器要大,速度比内存快。

        上图中,越往上,速度就越快,空间就越小,成本就越高。编译器优化,把本身从内存读取的值,优化成从寄存器或者L1缓存、L2缓存、L3缓存中读取。

        编译器优化,并非是100%触发,根据不同的代码结构,可能产生出不同的优化效果。形如下面的代码

import java.util.Scanner;public class Demo2 {private static int flag = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag == 0) {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1线程结束");});Thread t2 = new Thread(() -> {Scanner in = new Scanner(System.in);System.out.println("请输入flag的值:");flag = in.nextInt();System.out.println("t2线程结束");});t1.start();t2.start();t1.join();t2.join();}
}

        虽然没写volatile,但是加了sleep也不会触发上述优化:1. 循环速度大幅度降低了;2. 有了sleep之后,一次循环的瓶颈就不是load,在于sleep上,此时优化也没什么用;3. sleep本身会触发线程调度,调度过程触发上下文切换,再次加载也会触发这个值重新读取了。

        如下代码,我们改为一个静态成员变量count,会发现count也会触发优化。

import java.util.Scanner;public class Demo2 {private static int flag = 0;private static int count = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag == 0) {count++;}System.out.println("t1线程结束");});Thread t2 = new Thread(() -> {Scanner in = new Scanner(System.in);System.out.println("请输入flag的值:");flag = in.nextInt();System.out.println("t2线程结束");});t1.start();t2.start();t1.join();t2.join();}
}

1.3. volatile与synchronized的区别

public class Demo3 {private static volatile int count = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {count++;}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {count++;}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

        volatile这个关键字,能够解决内存可见性引起的线程安全问题,但是不具备原子性这样的特点。synchronized和volatile是两个不同的维度,synchronized是针对两个线程进行修改,而volatile是读取一个线程,另一个修改。

二、wait和notify

        因为线程调度的顺序是不确定的,那我们就得保证每一种可能下都是正确的,就有点难搞了。我们之前提到过,join()方法可以控制线程的结束顺序。两个线程在运行的时候,我们希望是持续执行下去,但是两个线程中的某些环节,我们希望是能够有一定的顺序。

        例如,假设有线程1和线程2。我们希望线程1先执行完某个逻辑后,再让线程2执行,此时就可以让线程2通过wait()主动进行阻塞,让线程1先参与调度。等线程1执行完对应的逻辑后,就可以通过notify()唤醒线程2。

        另外wait和notify也能解决线程饿死的问题。线程饿死指的是在多线程编程中,某个或某些线程由于长时间无法获取到执行所需的资源,导致其任务迟迟无法完成,甚至永远无法执行的情况。 简而言之,就是某个线程“饿着肚子”等了很久,但一直没能得到“食物”。

        如下图所示,当一个滑稽老铁进入ATM机里面取钱时,会进行上锁,其他滑稽老铁就必须在外面阻塞等待。当先进去的滑稽老铁发现ATM机里面没钱,便出去,而后又怀疑自己是不是看错了,于是又再次进入ATM机……如此循环往复,造成其他线程无法去CPU上执行,导致线程饿死。

        线程饿死不像死锁那么严重。死锁发生之后,就会僵持住,除非程序重启,否则一直卡住。线程饿死,其他线程还是有一定机会拿到锁的,只是拿到锁的时间会延迟,降低程序的效率。

        注意:wait、notify、notifyAll都是Object类里的方法。Java中任何一个类,都会有上述三种方法。

2.1. wait()方法

public class Demo4 {public static void main(String[] args) {Object o = new Object();System.out.println("wait之前");o.wait();System.out.println("wait之后");}
}

        在Java标准库中,但凡涉及到阻塞类的方法,都有可能抛出InterruptedException异常,所以我们这里也要在前面加上InterruptedException异常。

public class Demo4 {public static void main(String[] args) throws InterruptedException {Object o = new Object();System.out.println("wait之前");o.wait();System.out.println("wait之后");}
}

        但我们一运行程序之后,在打印“wait之前”语句后出现了IllegalMonitorStateException异常。此处的Monitor指的是sychronized,因为sychronized在JVM的底层实现被称为“监视器锁”。上面的异常是指锁的状态不符合预期。wait内部的第一件事就是释放锁,但释放锁的前提是得先拿到锁。像前面提到的滑稽老铁发现ATM机里面没有钱,如果滑稽老铁在里面等,意味着一直持有这个锁,其他人进不来。wait方法就要搭配sychronized使用。

public class Demo4 {public static void main(String[] args) throws InterruptedException {Object o = new Object();System.out.println("wait之前");synchronized (o) {o.wait();}System.out.println("wait之后");}
}

        此处的阻塞会持续进行,直到其他线程调用notify。

import java.util.Scanner;public class Demo5 {private static Object locker = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {System.out.println("t1等待之前");synchronized (locker) {try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1等到之后");});Thread t2 = new Thread(() -> {Scanner in = new Scanner(System.in);System.out.println("请输入任意内容,唤醒t1");in.next();// 必须是同一个锁对象synchronized (locker) {locker.notify();}});t1.start();t2.start();}
}

        wait要做的事情:

  • 使当前执行代码的线程进行等待(把线程放到等待队列中)​
  • 释放当前的锁
  • 满⾜⼀定条件时被唤醒,重新尝试获取这个锁

        使用wait的时候,阻塞其实是有两个阶段的:1. WAITING的阻塞,通过wait等待其他线程的通知;2. BLOCKED的阻塞,当收到通知之后,就会重新获取锁,可能又会遇到锁竞争。假设notify后面还有别的逻辑,此时锁就会多占用一会儿。

        默认情况下,wait的阻塞是死等。wait也可以设置参数等待时间的上限。

import java.util.Scanner;/*** @author gao* @date 2025/7/9 20:54*/public class Demo6 {private static Object locker = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {System.out.println("t1等待之前");synchronized (locker) {try {// t1在1000ms内没有收到任何通知,就会自动唤醒locker.wait(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1等待之后");});Thread t2 = new Thread(() -> {Scanner in = new Scanner(System.in);System.out.println("请输入任何内容,唤醒t1");in.next();synchronized (locker) {locker.notify();}});t1.start();t2.start();}
}

2.2. notify()方法

import java.util.Scanner;public class Demo7 {public static Object locker = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {System.out.println("t1等待之前");synchronized (locker) {try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1等待之后");});Thread t2 = new Thread(() -> {System.out.println("t2等待之前");synchronized (locker) {try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t2等待之后");});Thread t3 = new Thread(() -> {System.out.println("t3等待之前");synchronized (locker) {try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t3等待之后");});Thread t4 = new Thread(() -> {Scanner in = new Scanner(System.in);System.out.println("输入任意内容,唤醒一个线程:");in.next();synchronized (locker) {locker.notify();}});t1.start();t2.start();t3.start();t4.start();}
}

        这里我们就唤醒了t3线程,而其他两个线程还在阻塞等待。我们多运行几次,结果也会不同。注意,这里操作系统的随机调度并不是概率论里的概率均等,而是无法预测的。在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

2.3. notifyAll()方法

        使⽤notifyAll⽅法可以⼀次唤醒所有的等待线程。

import java.util.Scanner;public class Demo8 {private static Object locker = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {System.out.println("t1等待之前");synchronized (locker) {try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1等待之后");});Thread t2 = new Thread(() -> {System.out.println("t2等待之前");synchronized (locker) {try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t2等待之后");});Thread t3 = new Thread(() -> {System.out.println("t3等待之前");synchronized (locker) {try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t3等待之后");});Thread t4 = new Thread(() -> {Scanner in = new Scanner(System.in);System.out.println("输入任意内容,唤醒一个线程:");in.next();synchronized (locker) {locker.notifyAll();}});t1.start();t2.start();t3.start();t4.start();}
}

        如果没有任何对象在wait,凭空调用notify或者notifyAll也不会有任何副作用。


文章转载自:

http://Yex1bdfk.nnpfz.cn
http://8HSd2yfr.nnpfz.cn
http://1vqotxnk.nnpfz.cn
http://iqhYOnsj.nnpfz.cn
http://y5CkfC3L.nnpfz.cn
http://LiuVALqN.nnpfz.cn
http://7xn4z5Og.nnpfz.cn
http://OmimbN0n.nnpfz.cn
http://S5ZWY7WP.nnpfz.cn
http://qrYXUwtt.nnpfz.cn
http://KUOl6DiQ.nnpfz.cn
http://H1sp1yPf.nnpfz.cn
http://FAd55Ftn.nnpfz.cn
http://nj3gGcqW.nnpfz.cn
http://byIotaJC.nnpfz.cn
http://lptsbVYm.nnpfz.cn
http://JMjpWZAM.nnpfz.cn
http://rtp7aPdF.nnpfz.cn
http://EijeoVUM.nnpfz.cn
http://c9e5xCh4.nnpfz.cn
http://eu7YWJNW.nnpfz.cn
http://06Kkdb0B.nnpfz.cn
http://40EMZRAT.nnpfz.cn
http://UM9HNC8D.nnpfz.cn
http://V99Gz6ni.nnpfz.cn
http://s6z3f9E1.nnpfz.cn
http://1m9vo1AY.nnpfz.cn
http://oA8bNWZV.nnpfz.cn
http://5EdSffs1.nnpfz.cn
http://34z4Udgf.nnpfz.cn
http://www.dtcms.com/wzjs/707119.html

相关文章:

  • 思途做的旅游网站网站建设罗贤伟
  • 轻松做网站佛山网站到首页排名
  • 微信公众号怎么做网站发布公司信息的网站
  • wordpress 大站点建网站要多少钱一台
  • 建站网站软件8一站式装修的利弊
  • 做网站用微信收款还是支付宝典型的网站开发人员
  • 保洁公司网站源码网站说服力营销型网站策划
  • 网站开发零基础培训学校城市建设投资公司网站
  • 淄博网站seo公司大连建网站策划
  • 网站的建设期wordpress 编写手机主题
  • 北京网站排名推广wordpress文章签名插件
  • 优异网站免费做微信小程序
  • 广州南建站时间网页游戏排行榜推选新壹玩
  • 上海网站开发月薪多少钱什么是seo和sem
  • 织梦网站后台如何做百度关键词推广
  • 广州 Wix网站开发我做的静态网站怎么发布到网上
  • 简单网站建设视频搭建电商平台
  • 官网和门户网站的区别福田商城网站建设哪家便宜
  • 局域网做网站 内网穿透网站域名注册时间查询
  • 广州骏域网站动态广告怎么做出来的
  • 专业制作外贸网站无锡新闻最新消息今天
  • 搜索引擎推广费用惠州seo招聘
  • 网站后台动态播放怎么做的成品网站nike源码1688免费
  • 网站推广策划书怎么说建立一个公司的网站吗
  • 优秀html5网站网站建设公司发展
  • 安徽省工程建设协会网站北京做网站开发公司电话
  • 邯郸网站建设小霖淘宝店铺怎么装修
  • 通过网站开发工具怎么改自动跳网站丝芭传媒有限公司
  • 做弩的网站网站专题页面策划
  • 电商网站开发流程代码小程序模板套用教程