1.什么是JUC
java.util工具包,分类
业务:普通的线程代码 Thread
Runnable:没有返回值
2.线程和进程
进程:一个应用程序
线程:一个进程可以包含多个线程,至少包含一个,Java默认有2个线程,main和GC守护线程
线程:开了一个进程Typora,写字,自动保存(线程负责)
Thread Runnable Callable
java真的可以开启线程吗?开不了的
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
//调用本地方法,底层的C++,Java无法直接操作硬件
private native void start0();
并发和并行
并发编程:并发,并行
并发:(多个线程操作同一个资源)
并行:(多个人一起行走)
多核cpu下才会产生并行:多个线程一起执行,线程池
并发编程的本质:充分利用CPU的资源
所有的公司都很看重!
线程有几个状态:
public enum State {
//新生
NEW,
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待
WAITING,
//超时等待
TIMED_WAITING,
//终止
TERMINATED;
}
wait/sleep区别:
1.来自不同的类
wait–>Object
sleep–》Thread
2.关于锁的释放
wait会释放锁,sleep睡觉了,抱着锁睡觉,不会释放
3.使用的范围是不同的
wait:必须在同步代码块中
sleep:可以在任何地方使用
3.Lock锁(重点)
Lock接口:
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
FairSync()公平锁:十分公平,可以先来后到
NonfairSync()非公平锁:十分不公平,可以插队(默认)
使用前加锁
package com.example;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Package: com.example
* @ClassName: SaleTicketDemo01
* @Author: lx
* @CreateTime: 2020/9/4 14:35
* @Description:基本的卖票
* 公司中的开发降低耦合性
* 线程就是一个单独的资源类,没有任何附属的操作
* 1.属性,方法
*/
public class SaleTicketDemo02 {
public static void main(String[] args) {
//并发:把资源类丢入线程,jdk1.8,lambda表达式(参数)-{代码}
Ticket1 ticket1=new Ticket1();
new Thread(()->{
for (int i = 0; i < 60; i++) {
ticket1.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 60; i++) {
ticket1.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 60; i++) {
ticket1.sale();
}
},"C").start();
}
}
//资源类
/*
* Lock三部曲:
* 1.new ReentrantLock();//
* 2.Lock.lock();//加锁
* 3.lock.unlock();//解锁
* */
class Ticket1{
//属性,方法
private int number=50;
Lock lock=new ReentrantLock();
//卖票的方式,本质:队列,锁
public synchronized void sale(){
lock.lock();
try {
if(number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第几张票"+(number--)+"剩余"+number);
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
Synchronized和Lock区别
1.Synchronized内置的Java关键字 Lock是一个Java类
2.Synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁
3.Synchronized: 会自动释放锁,lock必须要手动释放锁,如果不释放锁,会产生死锁
4.Synchronized:线程一获得锁阻塞,线程2等待;Lock则不会等待
5.Synchronized:可重入锁,不可以中断的,非公平的Lock,可重入锁,可以判断,非公平的(可以自己设置)
6.Synchronized:适合锁少量的代码同步问题,Lock适合锁大量的同步代码
锁是什么,如何判断锁是谁?
4.生产者和消费者问题
面试的:单例模式,排序算法,生产者和消费之,死锁
生产者和消费者:Synchronized
问题存在:A,B,C,D四个线程,此时应使用while而不是if判断
package com.example.PC;
/**
* @Package: com.example.PC
* @ClassName: A
* @Author: lx
* @CreateTime: 2020/9/4 15:06
* @Description:线程之间的通信问题,生产者和消费者问题,等待唤醒,通知唤醒
* 线程交替操作 AB操作同一个变量 num=0
* A num+1
* B num-1
*/
public class A {
public static void main(String[] args) {
Data data=new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//判断等待 业务 通知
class Data{//资源类
private int number=0;
//+1
public synchronized void increment() throws InterruptedException {
while (number!=0){
this.wait();
}
number++;//通知其他线程加一完毕
System.out.println(Thread.currentThread().getName()+"====>"+number);
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
while (number==0){
this.wait();
}
number--;//通知其他线程减一完毕
System.out.println(Thread.currentThread().getName()+"====>"+number);
this.notifyAll();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YZ3hnJ0F-1599722070347)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200904153051454.png)]
代码实现:
package com.example.PC;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Package: com.example.PC
* @ClassName: A
* @Author: lx
* @CreateTime: 2020/9/4 15:06
* @Description:线程之间的通信问题,生产者和消费者问题,等待唤醒,通知唤醒 线程交替操作 AB操作同一个变量 num=0
* A num+1
* B num-1
*/
public class B {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
}
//判断等待 业务 通知
class Data2 {//资源类
private int number = 0;
//+1
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
lock.lock();
try {
while (number != 0) {
condition.await();//等待
}
number++;//通知其他线程加一完毕
System.out.println(Thread.currentThread().getName() + "====>" + number);
condition.signalAll();//唤醒全部
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
;
}
}
//-1
public void decrement() throws InterruptedException {
lock.lock();
try {
while (number == 0) {
condition.await();//等待
}
number--;//通知其他线程减一完毕
System.out.println(Thread.currentThread().getName() + "====>" + number);
condition.signalAll();//唤醒全部
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
任何一个新的技术绝不仅仅是覆盖原来的技术
Condition:精准的通知和唤醒线程
package com.example.PC;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Package: com.example.PC
* @ClassName: C
* @Author: lx
* @CreateTime: 2020/9/4 15:43
* @Description:每个线程依次调用
*/
public class C {
public static void main(String[] args) {
Data3 data3 = new Data3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printA();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printB();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printC();
}
}, "C").start();
}
}
//
class Data3 {
private Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
private int number = 1;//1A 2B 3C
public void printA() {
lock.lock();
try {
//业务,判断 执行 通知
while (number != 1) {
//等待
condition.await();
}
System.out.println(Thread.currentThread().getName() + "===>" + number);
;
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
//业务,判断 执行 通知
while (number != 2) {
//等待
condition2.await();
}
System.out.println(Thread.currentThread().getName() + "===>" + number);
;
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (number != 3) {
//等待
condition3.await();
}
System.out.println(Thread.currentThread().getName() + "===>" + number);
;
number = 1;
condition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//生产线:下单-》支付-》交易->物流
}
5. 8锁现象
如何判断锁是谁,
new this具体的一个手机
class 固定的一个类
6.集合不安全的
package com.unsafe;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @Package: com.unsafe
* @ClassName: ListTest
* @Author: lx
* @CreateTime: 2020/9/4 17:01
* @Description:
*/
public class ListTest {
public static void main(String[] args) {
/*
并发下ArrayList是线程不安全的,
解决方法:
List<String> list=new Vector<>();
* List<String> list= Collections.synchronizedList(new ArrayList<>());
* List<String>list=new CopyOnWriteArrayList<>();
CopyOnWrite:写入时复制,COW计算机程序设计领域的一种优化策略
* * */
//多线程调用的时候,LIst读取的时候固定的,写入(覆盖)
//再写入的时候避免覆盖,造成数据问题
//读写分离 MyCat
//CopyOnWriteArrayList 比Vector强在哪里?
/*
*
* */
}
}
hashset的底层?
public HashSet() {
map = new HashMap<>();
}
//hashset的add方法
//add set本质就是put map的key是无法重复的,因此set是无序的
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
private static final Object PRESENT = new Object();//一个固定的不变的值
Map是不安全的
7.Callable
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aTK6KgdV-1599722070349)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200905105613564.png)]
1.可以有返回值
2.可以抛出异常
3.方法不同run()/call()
package com.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @Package: com.callable
* @ClassName: CallableTest
* @Author: lx
* @CreateTime: 2020/9/5 10:57
* @Description:
*/
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread myThread=new MyThread();
FutureTask futureTask=new FutureTask(myThread);
new Thread(futureTask,"A").start();
Integer o =(Integer) futureTask.get();
System.out.println(o);
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("call");
return 12465;
}
}
细节:
1.有缓存
2.可能会发生阻塞
8.常用的辅助类
9.读写锁
10.阻塞队列
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jDYrOG8V-1599722070351)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200906103006501.png)]
四组API:
方式 | 抛出异常 | 有返回值,不会抛出异常 | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add | offer | put | offer |
移除 | remove | poll | take | poll |
检测队尾元素 | element | peek |
1.抛出异常
package com.bq;
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
/**
* @Package: com.bq
* @ClassName: test1
* @Author: lx
* @CreateTime: 2020/9/6 10:35
* @Description:
*/
public class test1 {
public static void main(String[] args) {
}
public void test1(){
ArrayBlockingQueue<Object> queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.add("a"));
System.out.println(queue.add("B"));
System.out.println(queue.add("V"));
System.out.println("==============");
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
}
}
2.不会抛出异常
package com.bq;
import com.example.PC.A;
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
/**
* @Package: com.bq
* @ClassName: test1
* @Author: lx
* @CreateTime: 2020/9/6 10:35
* @Description:
*/
public class test1 {
public static void main(String[] args) {
test2();
}
private static void test2(){
ArrayBlockingQueue blockingQueue=new ArrayBlockingQueue(3);
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("a"));
System.out.println("==========");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
}
}
3.阻塞等待
4.超时等待
11、线程池
线程池:三大方法,七大参数,四种拒绝策略
程序的运行,本质就是占用系统的资源!优化资源的使用就是池化技术
线程池,连接池,内存池,对象池//创建和销毁十分浪费资源
池化技术:事先准备好一些资源,有人要用就来这里拿,用完后返还
1.最小的值
2.最大的值
线程池的好处:
1.降低资源的消耗
2.提高相应的速度
3.方便管理
线程复用:可以控制最大并发数,管理线程
三大方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4yjcGNDZ-1599722070353)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200906111012792.png)]
七大参数:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
//本质调用ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
int maximumPoolSize,//最大线程池大小
long keepAliveTime,//超时没有人调用就会释放
TimeUnit unit,//超时单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory,//创建线程
RejectedExecutionHandler handler) {//拒绝策略
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
12.四大函数式接口
lambda表达式,链式编程,函数式接口,stream流式计算
1.函数式接口:只有一个方法的接口
1.有一个输入参数,有一个输出
2.只要是函数式接口,可以用lambda表达式简化
2.断定型接口:有一个输入参数,返回值只能是布尔值
3.消费者接口,只有输入,没有返回值
4.供给型接口:该接口对应的方法类型为不接受参数,但是提供一个返回值,
13.Stream流式计算
什么是流式计算?
大数据:存储+计算
集合+Mysql本质就是存储东西的
计算都应该交给流来操作
14、ForkJoin
什么是ForkJoin?
ForkJoin在jdk1.7,并行执行任务
ForkJoin特点:工作窃取
这里面维护的都是双端队列
15.异步回调
16.JMM
请你谈谈你对Volatile的理解
是Java虚拟机提供的轻量级的同步机制
1.保证可见性
2.不保证原子性
3.禁止指令重排
什么是JMM?
Java内存模型,不存在的,概念和约定
关于JMM的一些同步的约定:
1.线程解锁前,必须把共享变量立刻刷回主存
2.线程加锁前,必须读取主存中的最新值到工作内存中
3.加锁和解锁是同一把锁
线程 工作内存 主存
- read 读取,作用于主内存把变量从主内存中读取到本本地内存。
- load 加载,主要作用本地内存,把从主内存中读取的变量加载到本地内存的变量副本中
- use 使用,主要作用本地内存,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。、
- assign 赋值 作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
- store 存储 作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作。
- write 写入 作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中。
- lock 锁定 :作用于主内存的变量,把一个变量标识为一条线程独占状态。
- unlock 解锁:作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
- 同时在Java内存模型中明确规定了要执行这些操作需要满足以下规则:
- 不允许read和load、store和write的操作单独出现。
- 不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中。
- 不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中。
- 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。即就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
- 一个变量在同一时刻只允许一条线程对其进行lock操作,lock和unlock必须成对出现
- 如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值
- 如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
- 对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vF37inTO-1599722070354)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200908092202785.png)]
问题:程序不知道主存中的值已经被修改了
2.不保证原子性
原子性:不可分割
线程A在执行任务的时候,不能被打扰的,也不能被分割,要么同时成功,要么同时失败
17.玩转单例模式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PJlpLEip-1599722070356)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200908161344469.png)]
双重检测锁加指令重拍加关键字判断依旧无法阻止反射破坏单例模式
package com.single;
/**
* @Package: com.single
* @ClassName: LazyMan
* @Author: lx
* @CreateTime: 2020/9/8 15:51
* @Description:
*/
public class LazyMan {
private LazyMan(){
synchronized (LazyMan.class){
if(lx==false){
lx=true;
}else{
throw new RuntimeException("别搞了老弟");
}
if(lazyMan!=null){
throw new RuntimeException("别搞了老弟");
}
}
}
//双重检测锁加指令重排
private static boolean lx=false;
private volatile static LazyMan lazyMan;
//双重检测锁模式的,懒汉式 DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
synchronized (LazyMan.class){
if(lazyMan==null){
lazyMan=new LazyMan();//不是一个原子性操作
lx=true;
/*
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把这个对象指向这个空间
* */
}
}
}
return lazyMan;
}
//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
反射无法破坏枚举:
package com.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @Package: com.single
* @ClassName: EnumSingle
* @Author: lx
* @CreateTime: 2020/9/8 16:07
* @Description:
*/
//enum枚举是什么?本身也是一个Class类
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance1 = declaredConstructor.newInstance();
EnumSingle instance2 = declaredConstructor.newInstance();
//在类中没有空参的构造方法
System.out.println(instance1);
System.out.println(instance2);
}
}
19.深入理解CAS
什么是CAS?