JUC-3
13、Stream流式计算
什么是Stream流式计算
- 大数据∶存储+计算
- 集合、MySQL本质就是存储东西的﹔
- 计算都应该交给流来操作!
14、ForkJoin
什么是ForkJoin
ForkJoin在JDK 1.7,并行执行任务!提高效率。大数据量!
大数据:Map Reduce (把大任务拆分为小任务)
ForkJoin特点:工作窃取(a线程完成帮b完成最后一部分)
这个里面维护的都是双端队列
@Test
public void test1(){
long sum=0l;
long start=System.currentTimeMillis();
for (int i = 1; i <= 10_0000_0000; i++) {
sum+=i;
}
long end=System.currentTimeMillis();
System.out.println("sum= "+sum+" time= "+(end-start));//289
}
//并行流
@Test
public void test2(){
long start=System.currentTimeMillis();
long sum= LongStream.rangeClosed(0l,10_0000_0000l).parallel().reduce(0,Long::sum);//sum();
//返回有序顺序 IntStream从 startInclusive (含)至 endInclusive通过的递增步长(含) 1 。
//可以使用for循环顺序地产生递增值的等效序列,如下所示:
// for (int i = startInclusive; i <= endInclusive ; i++) { ... }
long end=System.currentTimeMillis();
System.out.println("sum= "+sum+" time= "+(end-start));//195 187
}
15、异步回调
Future设计的初衷:对将来的某个事件的结果进行建模
Future
计算的结果。 提供方法来检查计算是否完成,等待其完成,并检索计算结果。 结果只能在计算完成后使用方法get
进行检索,如有必要,阻塞,直到准备就绪。
@Test
public void test3() throws ExecutionException, InterruptedException {
CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+" 000");
});
System.out.println("11111111");
runAsync.get();//获取阻塞执行结果
}
16、JMM
什么是JMM
JMM : Java内存模型,不存在的东西,概念!约定!
关于JMM的一些同步的约定︰
1、线程解锁前,必须把共享变量立刻刷回主存。
2、线程加锁前,必须读取主存中的最新值到工作内存中!
3、加锁和解锁是同一把锁
线程工作内存、主内存
8种操作:
问题,线程B修改了值,但是线程A不能及时可见
17、Volatile
请你谈谈你对Volatile的理解
Volatile是Java虚拟机提供轻量级的同步机制
1、保证可见性
public class Day92700 {
//不加vo1atile程序就会死循环!
// 加volatile 可以保证可见性
volatile static int num=0;
public static void main(String[] args) {
new Thread(()->{
while (num==0){
}
}).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
num=1;
System.out.println(num);
}
2、不保证原子性
原子性:不可分割
线程A在执行任务的时候,不能被打扰的,也不能被分割。要么同时成功,要么同时失败。
如果不加lock和synchronized,怎么样保证原子性
使用原子类,解决原子性问题
/ / volatile不保证原子性/原子类的Integer
private volatile static AtomicInteger num = new AtomicInteger();
public static void add(i
/ num++;(/不是一个原子性操作
num.getAndIncrement(); l/ AtomicInteger + 1方法,CAS
}
public static void main( String[] args) {
/理论上num结果应该为2万
for (int i = 1; i <= 20; i++) {
new Thread(()->i
for (int j = ; j < 1000 ; j++) {
add();
}
}).start();
}
这些类的底层都直接和操作系统挂钩! 在内存中修改值!Unsafe类是一个很特殊的存在!
3、禁止指令重排
什么是指令重排:
你写的程序,计算机并不是按照你写的那样去执行的。
源代码-->编译器优化的重排-->指令并行也可能会重排-->内存系统也会重排--->执行
处理器在进行指令重排的时候,考虑:数据之间的依赖性!
非计算机专业
volatile可以避免指令重排:内存屏障。CPU指令。作用:
1、保证特定的操作的执行顺序!
2、可以保证某些变量的内存可见性(利用这些特性volatile实现了可见性)
18、彻底玩转单例模式
//懒汉式单例
public class LazyMan i
private LazyMan()i
system.out.println(Thread.currentThread( ).getName( ) + "ok");
private volatile static LazyMan LazyMan;
/双重检测锁模式的懒汉式单例DCL懒汉式
public static LazyMan getInstance()i
if (LazyMan==nu11)i
synchronized (LazyMan.class){
if (LazyMan==nu11){
LazyMan = new LazyMan(); //不是—个原子性操作**
*1.分配内存空间
* 2、执行构造方法,初始化对象*
3、把这个对象指向这个空间*
*123*132A
*B [/此时LazyMan还没有完成构造*入
}
I
}
}
return lazyMan;
}
单例不安全,反射
枚举
枚举类型可以取代以往常量的定义方式,即将常量封装在类或接口中。此外,枚举类型还提供了安全检查功能。枚举类型本质上还是以类的形式存在。
1、使用枚举类型设置常量
以往设置常量,通常将常量放置在接口中,这样在程序中就可以直接使用了,并且该常量不能被修改,因为在接口中定义的常量时,该常量的修饰符为final与static。
19、深入理解CAS
public class Day10500 {
public static void main(String[] args) {
// CAScompareAndSet :比较并交换!
AtomicInteger atomicInteger = new AtomicInteger(2020);
//期望、更新
// public final boolean compareAndSet(int expect, int update)/
// 如果我期望的值达到了,那么就更新,否则,就不更新
atomicInteger.compareAndSet(2020,2023);
System.out.println(atomicInteger.get());//2023
}
}
Java无法操作内存
Java可以调用c++ native
C++可以操作内存
Java的后门.可以通过unsafe这个类操作内存
CAS∶比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作!如果不是就一直循环!
缺点∶
1、循环会耗时
2、一次性只能保证一个共享变量的原子性3、ABA问题
CAS : ABA问题(狸猫换太子)
20、原子引用
7.【强制】所有的相同类型的包装类对象之间值的比较,全部使用equals方法比较。
说明:对于Integer var = ?在-128至127之间的赋值,Integer对象是在
IntegerCache. cache产生,会复用己有对象,这个区间内的Integer值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用equals方法进行判断。
带版本号的原子操作!
package demo05;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;
public class Day10502 {
public static void main(String[] args) {
//’正常在业务操作,这里面比较的都是—个个对象
AtomicStampedReference<Integer> reference = new AtomicStampedReference<>(0, 1);
//AtomicStampedReference 注意,如果泛型是一个包装类,注意对象的引用问题
new Thread(()->{
int stamp=reference.getStamp();//获得版本号
System.out.println("a1=>"+stamp);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(reference.compareAndSet(0, 1, reference.getStamp(), reference.getStamp() + 1));
System.out.println("a2=>"+reference.getStamp());
System.out.println(reference.compareAndSet(1, 0, reference.getStamp(), reference.getStamp() + 1));
System.out.println("a3=>"+reference.getStamp());
},"a").start();
///乐观锁的原理相同!
new Thread(()->{
int stamp=reference.getStamp();//获得版本号
System.out.println("b1=>"+stamp);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(reference.compareAndSet(0, 6, stamp, stamp + 1));
System.out.println("b2=>"+reference.getStamp());
},"b").start();
}
}
21、各种锁的理解
1、公平锁、非公平锁
- 公平锁:非常公平,不能够插队,必须先来后到!
- 非公平锁:非常不公平,可以插队(默认都是非公平)
2、可重入锁
synchronized
class Phone{
public synchronized void sms ({
system.out.println(Thread.currentThread(). getName() + "sms ");ca11();//这里也有锁
}
public synchronized void ca11o{
system. out.print1n(Thread.currentThread(). getName() + "ca17");
}
}
lock
class Phone2{
Lock lock = new ReentrantLock();
public void sms(){
lock.lock();//细节问题: Lock.Lock( ); lock .unLock();
// lock锁必须配对,否则就会死在里面lock . lock();
try {i
System.out.println(Thread.currentThread().getName() + "sms" );call();//这里也有锁
catch (Exception e){
e.printstackTrace();}finally i
lock.unlock();lock.unlock();
3、自旋锁
package demo05;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
//自旋锁
public class Day10600 {
AtomicReference<Thread> atomicReference=new AtomicReference<>();
//加锁
public void mylock(){
Thread thread=Thread.currentThread();
System.out.println(thread.getName()+"---mylock");
//自旋锁
while (!atomicReference.compareAndSet(null,thread)){
}
}
//解锁
public void myunlock(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+"---myunlock");
atomicReference.compareAndSet(thread,null);
}
public static void main(String[] args) throws InterruptedException {
Day10600 day10600 = new Day10600();
new Thread(()->{
day10600.mylock();
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
day10600.myunlock();
}
},"aa").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
day10600.mylock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
day10600.myunlock();
}
},"bb").start();
}
}
aa---mylock
bb---mylock
aa---myunlock
bb---myunlock
4、死锁
解决问题
1、使用jps -1定位进程号
2、使用 jstack查看进行信息
面试,工作中!排查问题:
1、日志
2、堆栈