基本概念
- 线程:
cpu
调度的基本单位 - 进程:程序执行的基本单位 资源分配的基本单位
- 程序运行过程: cpu-读取指令–pc(存储指令地址),register(计算) 回写–执行下一条指令
- 并发:CPU 一核 ,模拟出来多条线程,天下武功,唯快不破,快速交替
- 并行:CPU 多核 ,多个线程可以同时执行; 线程池
wait与sleep的区别
1、来自不同的类
wait => Object
sleep => Thread
2、关于锁的释放
wait 会释放锁,sleep 睡觉了,抱着锁睡觉,不会释放!
3、使用的范围是不同的
wait必须在同步代码块中
sleep 可以再任何地方睡
4、是否需要捕获异常
wait 可以不需要捕获异常
sleep 必须要捕获异常
Synchronized 和 Lock 区别
-
Synchronized 内置的Java关键字, Lock 是一个Java类
-
Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
-
Synchronized 会自动释放锁,lock 必须要手动释放锁!如果不释放锁,死锁
-
Synchronized 线程 1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下
去;
-
Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以
自己设置);
-
Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码!
并发编程的三个特性
- 可见性
- 原子性
- 有序性
阻塞队列 BlockingQueue
方式 | 抛出异常 | 有返回值,不抛出异常 | 阻塞 等待 | 超时等待 |
---|---|---|---|---|
添加 | add | offer() | put | offer(-,时间,单位) |
移除 | remove | poll() | take | poll(时间,单位) |
检查队首元素 | element | peek | - | - |
线程池
两种方式:
-
使用Executors(自动的线程池,不推荐)
package com.kuang.pool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; // Executors 工具类、3大方法 public class Demo01 { public static void main(String[] args) { ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线 程 // ExecutorService threadPool = Executors.newFixedThreadPool(5); // 创建一 个固定的线程池的大小 // ExecutorService threadPool = Executors.newCachedThreadPool(); // 可伸缩 的,遇强则强,遇弱则弱 try {for (int i = 0; i < 100; i++) { // 使用了线程池之后,使用线程池来创建线程 threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+" ok"); }); } } catch (Exception e) { e.printStackTrace(); } finally { // 线程池用完,程序结束,关闭线程池 threadPool.shutdown(); } } }
-
手动创建线程,使用
ThreadPoolExecutor
package com.kuang.pool; import java.util.concurrent.*; // Executors 工具类、3大方法 /*** new ThreadPoolExecutor.AbortPolicy() // 银行满了,还有人进来,不处理这个人的,抛出异 常 * new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里! * new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常! * new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和等待队列中最早的竞争,也不会 抛出异常! */ public class Demo01 { public static void main(String[] args) { // 自定义线程池!工作 ThreadPoolExecutor ExecutorService threadPool = new ThreadPoolExecutor( 2, //核心线程池大小 5,// 最大核心线程池大小 3, // 超时了没有人调用就会释放 TimeUnit.SECONDS, // 超时单位 new LinkedBlockingDeque<>(3), // 阻塞队列 Executors.defaultThreadFactory(), // 线程工厂:创建线程的,一般 不用动 new ThreadPoolExecutor.DiscardOldestPolicy()); //拒绝策略 队列满了,尝试去和 最早的竞争,也不会抛出异常! try { // 最大承载:Deque + max // 超过 RejectedExecutionException for (int i = 1; i <= 9; i++) { // 使用了线程池之后,使用线程池来创建线程 threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+" ok"); }); } } catch (Exception e) { e.printStackTrace(); } finally { // 线程池用完,程序结束,关闭线程池 threadPool.shutdown(); } } }
几种锁
cas
: CAS(Compare and swap)
即比较并交换,也是实现我们平时所说的自旋锁或乐观锁的核心操作。它的实现很简单,就是用一个旧的预期的值和内存值进行比较,如果两个值相等,就用新的值替换内存值,并返回 true。否则,返回 false。
java.util.concurrent
下使用了很多的cas
,如:AtomicBoolean
。
cas
的领个常见问题:
- ABA问题:可以使用版本号的方式解决。
- 原子性问题:只能保证一个共享变量的原子操作。
会调用c语言,利用了 CPU 的cmpxchg
指令完成比较并替换,在地层中调用汇编语言的lock锁。
可重入锁
package com.kuang.lock;
import javax.sound.midi.Soundbank;
// Synchronized
public class Demo01 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sms();
},"A").start();
new Thread(()->{ phone.sms();
},"B").start();
}
}
class Phone{
public synchronized void sms(){
System.out.println(Thread.currentThread().getName() + "sms");
call(); // 这里也有锁
}
public synchronized void call(){
System.out.println(Thread.currentThread().getName() + "call");
}
}
锁的升级
加锁可以使一段代码在同一时间只有一个线程可以访问,在增加安全性的同时,牺牲掉的是程序的执行性能,所以为了在一定程度上减少获得锁和释放锁带来的性能消耗,在 jdk6 之后便引入了“偏向锁”和“轻量级锁”,所以总共有4种锁状态,级别由低到高依次为:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。这几个状态会随着竞争情况逐渐升级。
注意:锁可以升级但不能降级。
锁 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
偏向锁 | 加锁和解锁不需要额外的消耗,和执行非同步方法相比仅存在纳秒级的差距 | 如果线程间存在锁竞争,会带来额外的锁撤销的消耗 | 适用于只有一个线程访问同步块场景 |
轻量级锁 | 竞争的线程不会阻塞,提高了程序的响应速度 | 如果始终得不到索竞争的线程,使用自旋会消耗CPU | 追求响应速度,同步块执行速度非常快 |
重量级锁 | 线程竞争不使用自旋,不会消耗CPU | 线程阻塞,响应时间缓慢 | 追求吞吐量,同步块执行速度较慢 |
volatile
volatile的特点
- 保证可见性
- 不保证原子性
- 禁止指令重排
懒汉模式双检索需要使用volatile吗?
需要!
如果在执行的过程中有可能会发生指令重排,如果没有使用volatile的话,就有可能会拿到未初始化的完成的(半初始化)的对象。
volatile不允许乱序执行:
两个语句之间存在内存屏障
内存屏障HostPot