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

微信小程序可以做电影网站吗安网多少钱

微信小程序可以做电影网站吗,安网多少钱,做网站软件要钱吗,小程序开发平台哪家产品好专栏: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://www.dtcms.com/a/544504.html

相关文章:

  • 计算机专业做网站的开题报告门户建设开源软件
  • js基础:08、构造函数(共享方法)、原型(prototype)、原型对象、(修改原型)toString方法、垃圾回收
  • 如何通过机器学习(如K-means、SVM、决策树)与深度学习(如CNN、LSTM)模型,进行全球气候变化驱动因素的数据分析与趋势预测
  • Docker篇6-项目app.py和flask_app.service配置和映射到docker中
  • 从零开始搭建 flask 博客(1)实验
  • 深入解析 Rust 解构模式:元组、结构体与枚举的精准拆解
  • 从零开始搭建 flask 博客实验(2)
  • 筑牢智算“地基”:华为以RAS理念重塑AIDC建设新模式
  • 跨网段耦合器助汽车零部件线实现PLC与MES跨网段互联
  • C#程序实现将Teradata的存储过程转换为Azure Synapse Dedicated SQL pool的存储过程
  • 小型购物网站模板设计网站页面教案
  • 免费购物网站淘宝建设网站首页
  • 成绩发布工具使用方法,附成绩分析教程
  • sward零基础学习:安装与配置
  • java求职学习day45
  • 【有源码】基于Hadoop与Spark的时尚精品店数据分析与可视化系统-基于多维度分析的零售时尚销售数据挖掘与可视化研究
  • Guava - Guava 基本工具 Preconditions、Optional
  • 北京的电商平台网站有哪些内容做网站要多少钱 知乎
  • 北京网站建设 shwl营销单页网站
  • RISC-V开源处理器实战:从Verilog RTL设计到FPGA原型验证
  • Flutter兼容性问题:Namespace not specified
  • MoreFixes
  • 工业厂区人数进出显示屏让排班更科学
  • 分数阶微积分有限差分法求解
  • 软件设计师知识点总结:面向对象技术(面向对象基础+UML)
  • 【案例教程】从入门到精通-AI支持下的-ArcGIS数据处理、空间分析、可视化及多案例综合应用
  • 低压配电系统的AI进化(系统篇)
  • 注册网站代码装修平台网络推广公司
  • vue需要学习的点
  • Kotlin保留小数位的三种方法