juc05--线程通信
目的:就是让线程间具有互相发送信号通信的能力。
概述核心:利用共享对象实现通信,这里的通信不是指传值,而是发送信号。目的:就是让线程间具有互相发送信号通信的能力。而且,线程通信可以实现,一个线程可以等待来自其他线程的信号。举个例子,一个线程B可能正在等待来自线程A的信号,这个信号告诉线程B数据已经处理好了。
线程通信开发中不免会遇到,需要所有子线程执行完毕通知主线程处理某些逻辑的场景。或者是 线程A 在执行到某个条件通知 线程B 执行某个操作。在java中,比较典型的就是:等待通知机制。
等待通知机制等待通知模式是 Java 中比较经典的线程通信方式。两个线程通过对同一对象调用等待 wait() 和通知 notify() 方法来进行通讯。这种方式,有三个参与者:
阻塞线程 wait()
唤醒线程 notify()
monitor锁
看个最简单的例子:
12345678910111213141516171819202122232425262728293031323334353637383940414243public class TestWaitNotify4 { ...
juc04-验证线程处于临时状态
临时状态当一个线程被启动时,并不代表线程就有了执行权。线程处于临就绪状态并没有执行权,这个时候 main 线程继续往下执行,有可能是别的线程先开始执行。
代码验证12345678910111213141516public static void main(String[] args) { Test test = new Test(); Thread t1 = new Thread(test); Thread t2 = new Thread(test); t1.start(); test.flag = true; t2.start();}public class Test implements Runnable { boolean flag = false; public void run() { System.out.println( Thread.currentThread().getName() + "--->" ...
JUC03-模拟线程不安全
前言很多时间,我们需要证明线程是不安全的,那就需要复现线程不安全的情况。怎么复现?通过代码构建不安全场景。
由于线程在执行的时候是异步的,当所有线程操作共享数据时,有可以能出现都已经进入判断的情况下,共享数据已被改变,但是其后线程不知道,当线程醒来的时候,直接开始运行,这样就会出现数据不全安的问题。
为什么能构建出来?多条语句操作一个共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导到共享数据的错误。
构建不安全场景通过多个线程,在不加锁的情况下,让多条线程竞争同一个资源。
构建多条线程12345678910DemoRunnable run = new DemoRunnable();Thread t1 = new Thread(run);Thread t2 = new Thread(run);Thread t3 = new Thread(run);Thread t4 = new Thread(run); t1.start();t2.start();t3.start();t4.start();
竞争资源下面的代码执行,预其结果,最后打印:0,而实际 ...
JUC多线程02--什么是上下文切换
上下文切换即,不同线程之间的切换。是存储和恢愎CPU 状态的过程,它使得线程执行能够从中断恢愎执行。上下文切换是需要开销的。
线程切换只在多核 CPU 中才有并不是,线程切换是CPU的功能,单核 CPU 也可以进行上下文切换。CPU 执行线程的粒度是通过给分个线程分配时间切片来实现的。在单核时代,一个系统也会开很多程序,每个程序都会等待CPU来执行并不会等会某一个线程执行完毕。比如单核时代玩 CS,可以边玩游戏边听千千静听。
CPU 通过切换时间分片来执行任务,切换前都会保存上一次任务的状态,这样下次再切回来的时候,可以继续执行当前这个状态。这种保存再切换回来的操作,就是一次上下文切换。
查看上下文切换在linux下,使用vmstat 进行查看:
执行:
1vmstat 10 10
查看一下结果:
123456789101112procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi ...
java-计算概率
简述有一个需求,就是计算一个请求的命中概率,这个命中的概率是作用于单次的请求,而非整体,也就是每一次请求过来都只有20%的命中率。
代码实现123456789101112131415161718192021import java.util.Random;public class ProbabilityDemo { public static void main(String[] args) { // 设置命中概率为20% double hitProbability = 0.2; // 创建随机数生成器 Random random = new Random(); // 生成一个0到1之间的随机数 double randomValue = random.nextDouble(); // 判断随机数是否小于等于命中概率 if (randomValue <= hitProbability) { System.out.pr ...
JUC 多线程01--线程、进程概念
进程正在进行中的程序。每一个进程至少有一个线程。当程序运行时在内存空间中开辟一片独立空间。每一个进程都有一个执行顺序。一个进程更象一个任务。进程的内存原理:
应用程序在执行时都会在内存中开辟一片内存空间并分配地址。进程用于标识这片空间,封装里面的控制单元。
而线程就是进程中的控制单元。线程在控制着进程的执行。
进程和内存每个进程都有自己的一套虚拟内存地址,用来给自己的进程空间编号。进程空间的数据同样以字节为单位,依次增加。从功能上说,虚拟内存地址和物理内存地址类似,都是为数据提供位置索引。进程的虚拟内存地址相互独立。因此,两个进程空间可以有相同的虚拟内存地址,如0x10001000。虚拟内存地址和物理内存地址又有一定的对应关系,对进程某个虚拟内存地址的操作,会被CPU翻译成对某个具体内存地址的操作。
创建进程进程和线程都是由系统来进行创建,JVM通过调用当前系进行开辟进行和线程的操作。
123456789101112131415import java.io.IOException;public class ProcessDemo { //在Java中如何开启一个进 ...
java final 的一些总结
特点final 的含义是最终的、不可改变的。总结了一下 final 的一些规则。
修饰"类"则类不能被继承,所以没有子类,final类中的方法默认是final的。可以提高效率。JDK中很多加final是这个原因的。编译期确认调哪个方法,所以更快。1.5以后这样做没有效果。
修饰"方法"则方法不能被重写,
修饰"成员变量"则变量不以被改变,即被修饰成了常量。只能被赋值一次。
不能修饰构造方法
父类中的private成员方法是不能被子类覆盖的,因为private类型的方法默认是隐式final类型的
final 的引用不能指向新的对象。
形参声明为 final,则方法内不能再改变其:
基础数据类型值不可被修改
传入对象不能再被 new
继承关系时,final 的方法将不会被子类重写。所以父类使用的仍是本类自己的方法。
final 类不可被继承。
C++ 也有final关键字,在C++11及以后的标准中引入了final,final关键字用于修饰类、成员函数和虚函数,表示它们是最终版本,不能被继承或重写。
代码示例
final修 ...
java 安装JDK
安装JDK有三种安装方式
tar包安装
yum安装
bin安装
三种安装方式任选其一即可,有各自的特点。
tar包安装步骤:
建立目录
下载安装包
配置环境变量
建立目录如果是在linux下,推荐在/usr/local/下创建目录,如果是mac,根据自己的习惯来。
1mkdir -p /usr/local/java
下载安装包
https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
解压安装包
12tar -zxvf jdk-8u221-linux-x64.tar.gzmv jdk1.8.0_221/ /usr/local/java/
设置环境变量
linux 的话就直接配置/etc/profile,mac也有这个文件,但是建议配置在用户配置文件~/.bash_profile,如果不存在就手动创建一个文件。
12345vim /etc/profileexport JAVA_HOME=/usr/local/java/jdk1.8.0_221export PATH=$PATH ...