
- 1、NEW 新建状态
- 2、RUNNABLE 运行状态
- 3、TERMINATED 销毁状态
- 4、BLOCK 阻塞状态
- 5、TIMED_WAITING 有限时间等待状态
- 6、WAITING 无线时间等待状态
- NEW 状态:创建线程还没 start
Thread t1 = new Thread(() -> System.out.println("这是一个线程"));
System.out.println(t1.getState());

- RUNNABLE 运行状态:在线程中的状态
Thread t2 = new Thread(()->{
while(true){
}
});
t2.start();
System.out.println(t2.getState());

- TERMINATED 当前线程执行完毕
Thread t1 = new Thread(() -> System.out.println("这是一个线程"));
t1.start();
Thread.sleep(100);
System.out.println(t1.getState());

- BLOCK 阻塞状态:两个线程对同一个资源进行加锁,一个线程先占用锁,另一个线程就处于 block 状态,下面的主线程先占用锁,一开始获取到 thread 线程是正在运行中的状态,主线程休眠 1 s,thread 线程执行到 synchronized 锁的位置,此时锁还在主线程中,所以此时需要等待锁释放,就是 block 状态
Object object1 = new Object();
Thread thread = new Thread(()->{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1){
}
});
thread.start();
synchronized (object1){
System.out.println(thread.getState());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getState());
}
- TIMED_WAITING :有限时间等待状态,在线程中调用 sleep 休眠
Thread t3 = new Thread(()->{
while(true){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t3.start();
Thread.sleep(100);
System.out.println(t3.getState());

Object object = new Object();
Thread t4 = new Thread(()->{
synchronized (object){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t4.start();
Thread.sleep(3000);
System.out.println(t4.getState());
Thread t5 = new Thread(()->{
synchronized (object){
object.notify();
}
});
t5.start();

/**
* 创建固定线程数
*/
ExecutorService service = Executors.newFixedThreadPool(2);
//创建任务
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
}
};
service.submit(runnable);
service.execute(runnable);
service.submit(runnable);
ExecutorService executorService = Executors.newCachedThreadPool();
//
for (int i = 0; i < 10; i++) {
executorService.execute(()->{
System.out.println("执行任务,线程" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
int finalI = i;
executorService.execute(()->{
System.out.println("执行任务" + finalI);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
System.out.println("添加任务,时间:" + new Date());
scheduledExecutorService.schedule(()->{
System.out.println("任务被执行,时间:" + new Date());
},2,TimeUnit.SECONDS);
ScheduledExecutorService scheduledExecutorService1 = Executors.newSingleThreadScheduledExecutor();
System.out.println("添加任务,时间 " + new Date());
scheduledExecutorService1.schedule(()->{
System.out.println("任务被执行,时间" + new Date());
},2,TimeUnit.SECONDS);
ExecutorService executorService = Executors.newWorkStealingPool();
for (int i = 0; i < 10; i++) {
int finalI = i;
executorService.execute(()->{
System.out.println("线程" + Thread.currentThread().getName() + "执行任务" + finalI);
});
}
while (!executorService.isTerminated()) {
}
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));
for (int i = 0; i < 10; i++) {
int finalI = i;
threadPoolExecutor.execute(()->{
System.out.println("线程" + Thread.currentThread().getName() + "执行任务" + finalI);
});
}

ThreadPoolExecutor threadPoolExecutor1 = new ThreadPoolExecutor(1,1,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(1));
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("当前任务被执行,执行时间:" + new Date() +
" 执行线程:" + Thread.currentThread().getName());
}
};
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
};

public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor1 = new ThreadPoolExecutor(1,1,10, TimeUnit.SECONDS,new LinkedBlockingQueue<>(1), new ThreadPoolExecutor.CallerRunsPolicy());
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("当前任务被执行,执行时间:" + new Date() +
" 执行线程:" + Thread.currentThread().getName());
}
};
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
}

public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor1 = new ThreadPoolExecutor(1,1,10, TimeUnit.SECONDS,new LinkedBlockingQueue<>(1), new ThreadPoolExecutor.DiscardPolicy());
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("当前任务被执行,执行时间:" + new Date() +
" 执行线程:" + Thread.currentThread().getName());
}
};
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
}

public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor1 = new ThreadPoolExecutor(1,1,10, TimeUnit.SECONDS,new LinkedBlockingQueue<>(1), new ThreadPoolExecutor.DiscardOldestPolicy());
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("当前任务被执行,执行时间:" + new Date() +
" 执行线程:" + Thread.currentThread().getName());
}
};
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
}

public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor1 = new ThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("自定义拒绝策略");
}
});
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("当前任务被执行,执行时间:" + new Date() +
" 执行线程:" + Thread.currentThread().getName());
}
};
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
threadPoolExecutor1.execute(runnable);
}

public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Object> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
int finalI = i;
executorService.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(finalI * 200);
} catch (InterruptedException e) {
e.printStackTrace();
}
OOMClass oomClass = new OOMClass();
list.add(oomClass);
System.out.println("执行任务:" + finalI);
}
});
}
}


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* ThreadPoolExecutor 演示示例
*/
public class ThreadPoolExecutorExample {
static class OOMClass {
// 创建 1MB 大小的变量(1M = 1024KB = 1024*1024Byte)
private byte[] data_byte = new byte[1 * 1024 * 1024];
}
public static void main(String[] args) throws InterruptedException {
// 手动创建线程池,最大线程数 2,最多存储 2 个任务,其他任务会被忽略
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 2,
0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2),
new ThreadPoolExecutor.DiscardPolicy()); // 拒绝策略:忽略任务
List<Object> list = new ArrayList<>();
// 添加任务
for (int i = 0; i < 10; i++) {
int finalI = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
// 定时添加
try {
Thread.sleep(finalI * 200);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 将 1m 对象添加到集合
OOMClass oomClass = new OOMClass();
list.add(oomClass);
System.out.println("执行任务:" + finalI);
}
});
}
// 关闭线程池
threadPool.shutdown();
// 检测线程池的任务执行完
while (!threadPool.awaitTermination(3, TimeUnit.SECONDS)) {
System.out.println("线程池中还有任务在处理");
}
}
}


- ①、当调用 shutdown 方法时,线程池会从 RUNNING 状态转换为 SHUTDOWN 状态,再到 TIDYING 状态,最后到 TERMINATED 状态
- ②、当调用 shutdownnow 方法时,线程池会从 RUNNING 状态转换为 STOP 状态,再到 TIDYING 状态,最后到 TERMINATED 状态
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
System.out.println("添加任务" + LocalDateTime.now());
scheduledExecutorService.schedule(new Runnable(){
@Override
public void run() {
System.out.println("执行 schedule 方法:" + LocalDateTime.now());
}
},2,TimeUnit.SECONDS);
}

public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
System.out.println("添加任务" + LocalDateTime.now());
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("执行 scheduleAtFixedRate 方法:" + LocalDateTime.now());
}
},3L,2L,TimeUnit.SECONDS);
}

public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
System.out.println("添加任务" + LocalDateTime.now());
scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
System.out.println("执行 scheduleWithFixedDelay 方法:" + LocalDateTime.now());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},3L,2L,TimeUnit.SECONDS);
}

public static void main(String[] args) {
// 创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 20,
0, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1024));
// 添加任务
addTask(threadPool);
// 打印结果
System.out.println("线程池任务执行完成!");
}
/**
* 给线程池添加任务
*/
private static void addTask(ThreadPoolExecutor threadPool) {
// 任务总数
final int taskCount = 5;
// 添加任务
for (int i = 0; i < taskCount; i++) {
final int finalI = i;
threadPool.submit(new Runnable() {
@Override
public void run() {
try {
// 随机休眠 0-4s
int sleepTime = new Random().nextInt(5);
TimeUnit.SECONDS.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("任务%d执行完成", finalI));
}
});
}
}

private static void isOver(ThreadPoolExecutor threadPool) {
threadPool.shutdown();
while(!threadPool.isTerminated()){
}
}

private static void isOver(ThreadPoolExecutor threadPool) {
while(threadPool.getCompletedTaskCount() != threadPool.getTaskCount()){
}
}

无需手动关闭线程池,但是二者返回的都是近似值,因为在线程池中任务和线程的状态可能是动态变化的,所以这里返回的是一个近似的值
3、CountDownLatch:可以理解为一个计数器,包含 N 个任务的计数器,没执行完一个任务,计数器 - 1,直到计数器为 0,任务线程池中任务都执行完毕
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,0,TimeUnit.SECONDS,new LinkedBlockingQueue<>(1024));
final int taskCount = 5;
CountDownLatch countDownLatch = new CountDownLatch(taskCount);
for (int i = 0; i < taskCount; i++) {
final int finalI = i;
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println("执行任务" + finalI);
countDownLatch.countDown();
}
});
}
countDownLatch.await();
System.out.println();
System.out.println("线程池任务执行完毕");
}

无需手动关闭线程池,但是 countdownlatch 只能用一次,不能复用,执行多个线程就会出现最上面的问题:

4、CyclicBarrier 循环计数器,可以复用的 countdownlatch
public static void main21(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,0,TimeUnit.SECONDS,new LinkedBlockingQueue<>(1024));
final int taskCount = 5;
CyclicBarrier cyclicBarrier = new CyclicBarrier(taskCount, new Runnable() {
@Override
public void run() {
System.out.println();
System.out.println("所有线程已经执行完毕");
}
});
for (int i = 0; i < taskCount; i++) {
final int finalI = i;
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println("执行任务" + finalI);
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}
for (int i = 0; i < taskCount; i++) {
final int finalI = i;
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println("执行任务" + finalI);
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}
}

public static void main1(String[] args) {
Thread thread = new Thread(()->{
System.out.println("用户线程");
});
System.out.println(thread.isDaemon());
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5,10,1, TimeUnit.SECONDS,new LinkedBlockingQueue<>(3));
poolExecutor.execute(()->{
System.out.println("ThreadPool为" +(Thread.currentThread().isDaemon() == true ? "守护线程" : "用户线程"));
});
}

public static void main2(String[] args) {
Thread thread = new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}

public static void main(String[] args) {
Thread thread = new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.setDaemon(true);
thread.start();
}

public static void main(String[] args) throws InterruptedException {
ThreadFactory threadFactory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
}
};
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10,20,1,TimeUnit.SECONDS, new LinkedBlockingQueue<>(5), threadFactory);
poolExecutor.execute(()->{
System.out.println("当前线程池线程为:" + (Thread.currentThread().isDaemon() ? "守护线程" : "用户线程"));
});
Thread.sleep(2000);
}



一共有七种方法:
class MyThread extends Thread{
@Override
public void run() {
System.out.println("创建线程方法1");
}
}
public static void main1(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
public static void main2(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
System.out.println("创建线程方法2");
}
};
thread.start();
}
class MyCallable implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("创建线程方法5");
return 0;
}
}
public static void main4(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
public static void main3(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("创建线程方法3");
}
});
thread.start();
}
public static void main5(String[] args) {
Thread thread = new Thread(()->{
System.out.println("创建线程方法5");
});
thread.start();
}
class MyCallable implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("创建线程方法5");
return 0;
}
}
public static void main6(String[] args) throws ExecutionException, InterruptedException {
MyCallable callable = new MyCallable();
FutureTask futureTask = new FutureTask(callable);
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get());
}
public static void main(String[] args) {
FutureTask futureTask = new FutureTask(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("创建线程方法7");
return 0;
}
});
Thread thread = new Thread(futureTask);
thread.start();
}
public static void main(String[] args) {
Thread thread1 = new Thread(()->{
System.out.println("执行 thread1");
});
thread1.run();
Thread thread2 = new Thread(()->{
System.out.println("执行 thread2");
});
thread2.start();
}

public static void main(String[] args) {
Thread thread1 = new Thread(()->{
System.out.println(Thread.currentThread().getName() + "执行 thread1");
});
thread1.run();
Thread thread2 = new Thread(()->{
System.out.println(Thread.currentThread().getName() + "执行 thread2");
});
thread2.start();
}


为了避免多线程并发问题,对于 wait 和 notify 都是需要等待队列存在的,如果不在 synchronized 中调用,就不会有等待队列的存在了,看下面这样阻塞队列的一个例子
public class MyBlockingQueue {
Queue<String> queue = new LinkedList<>();
public void put(String str){
queue.offer(str);
notify();
}
public String get() throws InterruptedException {
while(queue.isEmpty()){
wait();
}
return queue.remove();
}
}

public class MyBlockingQueue {
Queue<String> queue = new LinkedList<>();
public void put(String str){
synchronized (MyBlockingQueue.class){
queue.offer(str);
notify();
}
}
public String get() throws InterruptedException {
synchronized (MyBlockingQueue.class){
while(queue.isEmpty()){
wait();
}
}
return queue.remove();
}
}
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Thread thread = new Thread(()->{
synchronized (lock){
System.out.println("新线程获取到锁资源" + new Date());
try {
Thread.sleep(2000);
System.out.println("新线程释放到锁资源"+ new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
// Thread.sleep(200);
System.out.println(Thread.currentThread().getName() + " 线程尝试获取锁资源"+ new Date());
synchronized (lock){
System.out.println(Thread.currentThread().getName() + " 线程获取到锁资源"+ new Date());
}
}

可以发现直到新线程释放了锁,main 线程才获取到锁,所以 sleep 在休眠状态,也是不会释放锁的
wait 在休眠状态会释放锁资源:
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Thread thread = new Thread(()->{
synchronized (lock){
System.out.println("新线程获取到锁"+new Date());
try {
lock.wait(2000);
System.out.println("新线程释放锁"+new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
Thread.sleep(200);
System.out.println("main线程尝试获取锁"+new Date());
synchronized (lock){
System.out.println("main线程获取到锁"+new Date());
}
}

可以看到 wait 休眠期间是释放锁的
5、线程进入状态不同:sleep 是有限时间等待状态,wait 是无线时间等待状态



public static void main(String[] args) throws InterruptedException {
AtomicInteger count1 = new AtomicInteger(0);
Thread t1 = new Thread(()->{
for (int i = 0; i < 50000; i++) {
count1.incrementAndGet();
}
});
t1.start();
Thread t2 = new Thread(()->{
for (int i = 0; i < 50000; i++) {
count1.incrementAndGet();
}
});
t2.start();
t1.join();
t2.join();
System.out.println(count1);
}



public static void main(String[] args) throws InterruptedException {
ReentrantLock reentrantLock = new ReentrantLock();
Thread thread = new Thread(()->{
reentrantLock.lock();
for (int i = 0; i < 50000; i++) {
count++;
}
reentrantLock.unlock();
});
thread.start();
Thread thread1 = new Thread(()->{
reentrantLock.lock();
for (int i = 0; i < 50000; i++) {
count++;
}
reentrantLock.unlock();
});
thread1.start();
thread.join();
thread1.join();
System.out.println(count);
}

private static int number = 0;
public static void main(String[] args) throws InterruptedException {
ThreadLocal<Integer> count1 = ThreadLocal.withInitial(()->0);
Thread thread = new Thread(()->{
for (int i = 0; i < 50000; i++) {
count1.set(count1.get() + 1);
}
number += count1.get();
});
thread.start();
Thread thread1 = new Thread(()->{
for (int i = 0; i < 50000; i++) {
count1.set(count1.get() + 1);
}
number += count1.get();
});
thread1.start();
thread.join();
thread1.join();
System.out.println(number);
}


this 是当前对象的引用,valueofset 是变量的内存偏移地址,第三个参数是一个常量 1
通过上面的源代码可以发现,此处的自增方法调用的是 unsafe 类的 getandaddInt 方法

发现此时循环中就是 CAS 操作

此操作是获取到当前原子类对象的值 value

可以发现此时 value 是被 volatile 修饰的,保证内存可见性,防止读数据时直接从寄存器中读取

CAS 的实际操作就是:通过 var1 和 var2 拿到内存中实际的变量值,和预期值进行比较,数值一致,更新内存中的值为 var5 + var4,不一致,就一直循环到 CAS 操作执行成功
正如上面所示,原子类的自增通过 CAS 和 volatile 关键字实现了操作的原子性,从而保证了多线程并发情况下多个线程操作同一变量而产生的线程安全问题,但是这仅仅只适合于一些粒度比较小的需求才有效,如果比较复杂的业务逻辑还是需要加锁
CAS 的问题:
1、典型 ABA 问题,假如一个变量初始值为 A,修改为 B,然后又修改为 A ,再 ABA 看来,此时的变量的值是没有发生过变化的,所以会进行多次 CAS 操作,这就是 ABA 问题


2、自旋开销问题:当 CAS 发生问题时,如果资源竞争非常激烈,自旋时间长,会给 CPU 带来比较大的开销
3、只能保证单个变量的原子性,对多个共享变量的操作 CAS 是无法同时保证原子性的,此时需要采用加锁的方式,或者采用该类 AtomicReference
总结:CAS 是靠硬件来实现的从而在硬件层面提升效率,最底层还是交给硬件来保证原子性和可见性,实现方式是通过基于硬件平台的汇编指令,核心思想就是比较变量的值 V 和预期值是否一致,如果一致,交换不一致,自旋再来

中断是一种协作协商机制,Java 没有给中断添加任何语法,需要程序员自己实现
关于线程中断这里有三个 API 可以供我们使用:
interrupted 与 isinterrupted 区别:

可以看到两个方法调用都是底层的 native 方法,只是标识位传参值不一样,传 true 代表清除线程中断状态,传 false 代表不清除
1、设置标志位(使用 volatile 变量或者是原子类),当 while 中的标志位为设置为 true 线程即中断,这里使用 volatile 关键字,保证每次 flg 读取的都是内存中的值,防止内存可见性问题
private volatile static boolean flg = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while(!flg){
System.out.println("hello");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
Thread.sleep(1000);
flg = true;
}
//标志位
Thread.currentThread().isInterrupted())
//中断方法
thread.interrupt();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while(!Thread.currentThread().isInterrupted()){
System.out.println("hello");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
});
thread.start();
Thread.sleep(1000);
thread.interrupt();
}

public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while(!Thread.currentThread().isInterrupted()){
System.out.println("hello");
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// break;
// }
}
});
thread.start();
Thread.sleep(1000);
thread.interrupt();
}

public class Singleton1 {
private static Singleton1 instance = new Singleton1();
//因为是单例模型 只允许创建一次 实例 所以构造方法不对外
private Singleton1(){};
//通过 get 方法返回实例
public static Singleton1 getInstance(){
return instance;
}
}
private static volatile Singleton2 singleton2 = null;
private Singleton2(){};
public static Singleton2 getInstance(){
if(singleton2 == null){
synchronized (Singleton2.class){
if(singleton2 == null){
singleton2 = new Singleton2();
}
}
}
return singleton2;
}
这里采用双重锁校验机制 + volatile 关键字保证线程安全





3、静态内部类
public class Singleton3 {
//只能初始化一次
private Singleton3(){};
//静态内部类
private static class SingletonHolder{
private static final Singleton3 instance = new Singleton3();
}
//提供公共方法获取到实例
private static Singleton3 getInstance(){
return SingletonHolder.instance;
}
}
public enum Singleton4 {
INSTANCE;
public Singleton4 getInstance(){
return INSTANCE;
}
}
死锁是指两个或者两个以上单元对都在等待对方释放锁资源,但没有一方提起释放锁,从而造成了一种阻塞现象被称为锁

死锁的产生的原因:
死锁的产生需要同时满足上面的所有条件才会产生死锁
死锁如何解决:破坏掉任意一个或者多个条件即可


private static Object a = new Object();
private static Object b = new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (a){
System.out.println("线程1获取到 a 锁,尝试获取 b 锁");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b){
System.out.println("获取到 b 锁");
}
}
}).start();
new Thread(()->{
synchronized (b){
System.out.println("线程1获取到 b 锁,尝试获取 a 锁");
synchronized (a){
System.out.println("获取到 a 锁");
}
}
}).start();
}






内存屏障:是一种屏障指令,使得 CPU 或者编译器对屏障指令前后发出的内存操作执行排序的约束



看下面两个方法:

如上图就可能造成线程 1 在执行期间发生了指令重排序,然后此时先执行的是 flg = true 把标志位哦设置为了 true 此时线程二读到的是 true,就会打印 i 为 0,此时结果就和我们设置的思想偏差了,所以这就是指令重排序造成的问题,所以需要使用 volatile 修饰 flg,利用内存屏障去禁止指令的重排序,下面的示意图展示了 volatile 是如何通过内存屏障避免了指令重排序的问题


验证 volatile 可见性:





为什么 volatile 无法保证原子性:




volatile 的适用场景:
总结:

static ReentrantLock reentrantLock = new ReentrantLock(true);
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(()->{
for (int j = 0; j < 2; j++) {
reentrantLock.lock();
System.out.println("当前线程" + Thread.currentThread().getName());
reentrantLock.unlock();
}
});
thread.start();
}
}

static ReentrantLock reentrantLock1 = new ReentrantLock();
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(()->{
for (int j = 0; j < 2; j++) {
reentrantLock1.lock();
System.out.println("当前线程" + Thread.currentThread().getName());
reentrantLock1.unlock();
}
});
thread.start();
}
}

非公平锁,获取锁的顺序是 A -> A -> B -> B -> C -> C,原因是所有线程都争抢锁时,因为当前执行线程处于活跃状态,其他线程属于等待状态(还需要被唤醒),所以当前线程总是会先获取到锁,所以最终获取锁的顺序是:A -> A -> B -> B -> C -> C
执行流程:

优点分析:
public static void main(String[] args) {
Thread thread = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sleep 线程休眠");
});
thread.start();
}

public static void main(String[] args) {
Thread thread = new Thread(()->{
System.out.println("线程开始时间" + new Date());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
System.out.println("结束时间" + new Date());
});
thread.start();
}

public static void main(String[] args) {
Object lock = new Object();
Thread thread = new Thread(()->{
System.out.println("wait()开始前");
synchronized (lock){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait()开始后");
}
});
thread.start();
Thread thread1 = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("notify开始前");
synchronized (lock){
lock.notify();
}
System.out.println("notify开始后");
});
thread1.start();
}


public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Thread thread = new Thread(()->{
System.out.println("wait前");
lock.lock();
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait后");
lock.unlock();
});
thread.start();
Thread thread1 = new Thread(()->{
System.out.println("signal前");
lock.lock();
condition.signal();
System.out.println("signal后");
lock.unlock();
});
thread1.start();
}


public static void main(String[] args) {
Thread thread1 = new Thread(()->{
System.out.println("线程1休眠");
LockSupport.park();
System.out.println("线程1执行结束");
});
thread1.start();
Thread thread2 = new Thread(()->{
System.out.println("线程2休眠");
LockSupport.park();
System.out.println("线程2执行结束");
});
thread2.start();
Thread thread3 = new Thread(()->{
System.out.println("线程3唤醒线程1");
LockSupport.unpark(thread1);
});
thread3.start();
}




private Object object = new Object();
public void func(){
synchronized (object){
System.out.println("获取锁");
}
}

反编译后,一般都是两个 exit 对应一个 enter,第二个 exit 是代表如果获取锁期间发生异常情况,没有正常释放锁,走这里的第二个出口,第一个 exit 代表正常退出走的出口,极端情况下,也会有一对一的情况
2、同步方法:
public synchronized void m2(){
}
public static void main(String[] args) {
}



private static Object object = new Object();
public static void main(String[] args) {
synchronized (object){
System.out.println("外层执行");
synchronized (object){
System.out.println("内层执行");
}
}
}

class Student{
public synchronized void func1(){
System.out.println("执行 func1");
func2();
}
public synchronized void func2(){
System.out.println("执行 func2");
}
}
public static void main(String[] args) {
new Thread(()->{
new Student().func1();
}).start();
}

每一个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针,当执行 monitorenter 时如果目标对象的计数器为 0,证明没有线程持有此锁,那么就将该锁对象的指针指向该线程,计数器 + 1,在目标锁对象计数器不为 0 的情况下,如果锁对象持有线程是当前线程,那么就将计数器 + 1,否则进行等待,当执行 monitorexit 时计数器 - 1,计数器为 0 代表锁已经释放











package Thread;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2022-09-24
* Time: 14:32
*/
class clickNum{
int number;
public synchronized void clickBySynchronized(){
number++;
}
AtomicLong atomicLong = new AtomicLong(0);
public void clickByAtomicLong(){
atomicLong.getAndIncrement();
}
LongAdder longAdder = new LongAdder();
public void clickByLongAdder(){
longAdder.increment();
}
LongAccumulator longAccumulator = new LongAccumulator((x,y)-> x+y, 0);
public void clickLongAccumulator(){
longAccumulator.accumulate(1);
}
}
public class Thread10 {
private static final int ThreadNum = 50;
private static final int _1w = 10000;
public static void main(String[] args) throws InterruptedException {
clickNum clickNum = new clickNum();
CountDownLatch countDownLatch1 = new CountDownLatch(ThreadNum);
CountDownLatch countDownLatch2 = new CountDownLatch(ThreadNum);
CountDownLatch countDownLatch3 = new CountDownLatch(ThreadNum);
CountDownLatch countDownLatch4 = new CountDownLatch(ThreadNum);
long startTime = 0;
long endTime = 0;
startTime = System.currentTimeMillis();
for (int i = 1; i <= ThreadNum; i++) {
new Thread(()->{
try {
for (int j = 1; j <= 100 * _1w; j++) {
clickNum.clickBySynchronized();
}
}finally {
countDownLatch1.countDown();
}
},String.valueOf(i)).start();
}
countDownLatch1.await();
endTime = System.currentTimeMillis();
System.out.println("执行时间" + (endTime - startTime) + "\t" +clickNum.number);
startTime = System.currentTimeMillis();
for (int i = 1; i <= ThreadNum; i++) {
new Thread(()->{
try {
for (int j = 1; j <= 100 * _1w; j++) {
clickNum.clickByAtomicLong();
}
}finally {
countDownLatch2.countDown();
}
},String.valueOf(i)).start();
}
countDownLatch2.await();
endTime = System.currentTimeMillis();
System.out.println("执行时间" + (endTime - startTime) + "\t" +clickNum.atomicLong.get());
startTime = System.currentTimeMillis();
for (int i = 1; i <= ThreadNum; i++) {
new Thread(()->{
try {
for (int j = 1; j <= 100 * _1w; j++) {
clickNum.clickByLongAdder();
}
}finally {
countDownLatch3.countDown();
}
},String.valueOf(i)).start();
}
countDownLatch3.await();
endTime = System.currentTimeMillis();
System.out.println("执行时间" + (endTime - startTime) + "\t" +clickNum.longAdder);
startTime = System.currentTimeMillis();
for (int i = 1; i <= ThreadNum; i++) {
new Thread(()->{
try {
for (int j = 1; j <= 100 * _1w; j++) {
clickNum.clickLongAccumulator();
}
}finally {
countDownLatch4.countDown();
}
},String.valueOf(i)).start();
}
countDownLatch4.await();
endTime = System.currentTimeMillis();
System.out.println("执行时间" + (endTime - startTime) + "\t" + clickNum.longAccumulator.get());
}
}








锁优化的背景:用锁确实可以保证数据安全性,但是会带来性能下降,无锁虽然性能会提高,但是安全性会下降,那么锁升级就是为平衡这二者
synchronized 为重量级锁,因为 synchronized 效率低下,因为监视器锁是依赖底层的操作系统的系统互斥量来实现的,挂起和恢复都需要用户态和内核态之间的相互转换(这个过程效率是比较低效的),所以考虑减低获得锁和释放锁所带来的性能消耗,引入了轻量级锁和偏向锁
偏向锁:markword 存储的是偏向的线程 ID
轻量级锁:markword 存储的是指向线程栈中的 Lock Record 指针
重量级锁:markword 存储的是执行堆中的 monitor 对象的指针

class Sale{
public int count = 50;
Object object = new Object();
public synchronized void saleCount(){
synchronized (object){
if(count > 0){
System.out.println(Thread.currentThread().getName() + " 卖出 " + (count--) + " 还剩下 " + count);
}
}
}
}
public class Thread1 {
public static void main(String[] args) {
Sale sale = new Sale();
new Thread(()->{
for (int i = 0; i < 55; i++) {
sale.saleCount();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 55; i++) {
sale.saleCount();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 55; i++) {
sale.saleCount();
}
},"C").start();
}
}


Java 中的 synchronized 重量级锁是基于进入和退出 Monitor 对象实现的。在编译时期会在同步代码块插入 monitor enter 指令,结束位置会插入 monitor exit 指令。如果当前线程获取到锁对象,在其未释放前,其他线程无法获取到此锁对象

如果多个线程对多个对象加锁不产生锁冲突,或者在单线程下使用线程安全的类,编译器为了提高程序性能,会进行锁消除,比如下面的代码:


可以看到是 10 个线程操作 10 个不同的 object 所以 synchronized 锁也就没用了,所以这里编译器会进行锁消除,提高程序性能
方法中首尾相连,前后相邻都是一个锁对象,编译器就会把几个小块的同步代码块合并成一大块,加大锁的范围,一次申请释放就可以,避免多次申请和释放,提高性能,比如下面的代码在运行过程中就会发生锁粗化

编译器将上面的代码优化为:

用于实现锁或者其他同步组件的公共基础部分的抽象实现,是重量级基础框架及整个 JUC 的基石,主要用于锁分配给谁的问题

JUC 框架中的类,我们可以顺利使用的类(Reentrantlock、CountDownlatch)底层都是依赖于 AQS 实现的。
JUC 中会涉及到加锁问题,加锁就会造成阻塞,有阻塞就需要有排队,要排队就需要队列,来管理谁先谁后,谁是下一个获取锁的,谁又在队列中不想排列退出……,如果资源共享,就需要一定的等待唤醒机制来保证锁分配,这些规范 AQS 来进行统一的规范管理
AQS 将请求线程封装成一个个 Node 通过 CAS 自旋以及 LockSupport 的方式,维护 status 的状态,使并发到同步的效果

AQS 是一种抽象的队列同步器,作用是来保证等待状态下后续线程的唤醒机制

每个线程被封装成 Node 结点,结点之间组成双向链表,整个双向链表又构成一个队列。头指针指向首结点,尾指针指向尾结点,监视着状态位,当有线程占用,同步器中进行等待,当 status 状态位空闲,队列中形参新的通知唤醒机制,挨个去获取锁


首先 Reentrantlock 底子就是 AQS ,底层实现了 lock 接口,基本都是聚合了一个队列同步器的子类完成线程访问控制的

从非公平锁和公平锁的构造方法开始看:









import java.sql.Time;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2022-09-29
* Time: 9:47
*/
//资源类 模拟一个简单的缓存
class MyResoure{
Map<String,String> map = new HashMap<>();
//reentrantlock 等于 synchronized
Lock lock = new ReentrantLock();
//reentrantreadwritelock 一体两面 读写互斥 读读互斥
ReadWriteLock rwLock = new ReentrantReadWriteLock();
//写操作
public void write(String key, String value) throws InterruptedException {
lock.lock();
// rwLock.writeLock().lock();
//正在写入
try{
System.out.println(Thread.currentThread().getName() + " 正在写入");
map.put(key, value);
TimeUnit.MILLISECONDS.sleep(500);
System.out.println(Thread.currentThread().getName() + " 完成写入");
}finally {
// rwLock.writeLock().unlock();
lock.unlock();
}
}
//读操作
public void read(String key){
lock.lock();
// rwLock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName() + "正在读取");
String result = map.get(key);
//读比写块
TimeUnit.MILLISECONDS.sleep(2000);
System.out.println(Thread.currentThread().getName() + "读取完毕");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// rwLock.readLock().unlock();
lock.unlock();
}
}
}
public class ReentrantReadWriteLockDemo {
public static void main(String[] args) throws InterruptedException {
MyResoure resoure = new MyResoure();
for (int i = 1; i <= 10; i++) {
int finalI = i;
new Thread(()->{
//往缓存写入
try {
resoure.write(finalI +"", finalI +"");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
for (int i = 1; i <= 10; i++) {
int finalI = i;
new Thread(()->{
resoure.read(finalI+"");
}).start();
}
TimeUnit.SECONDS.sleep(1);
for (int i = 0; i < 3; i++) {
int finalI = i;
new Thread(()->{
//往缓存写入
try {
resoure.write(finalI +"", finalI +"");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}

写锁降级为读锁,类似 linux 的文件读写权限理解,就像是写权限高于读权限一样
读写锁演示:

StampLock 是 jdk 1.8 新增的读写锁,也是对 1.5 中的 reentrantreadwritelock 的优化。reentrantreadwritelock 实现了读写分离,但一旦读操作比较多的时候,想要获取写锁就比较难了,比如 1000 线程。999 个读,1个写,那么唯一一个写操作的线程就很难获取到写锁,因为有可能 999 个线程长时间占用锁,需要等到读锁释放才可以加写锁
StampLock 采用乐观锁(线程A在读的时候,认为其他线程修改数据的概率小)的方式获取锁后,其他线程尝试获取到写锁的时候不会阻塞,这其实是对读锁的优化,所以,在获取乐观读锁后,还需要对其结果进行校验
StampLock 完全可以实现 reentrantreadwritelock 的读写锁功能:
public class StampLockDemo {
static int number = 37;
static StampedLock stampedLock = new StampedLock();
public void write(){
long stamp = stampedLock.writeLock();
System.out.println(Thread.currentThread().getName() + " 准备写入");
try{
number = number + 13;
System.out.println(Thread.currentThread().getName() + " 写入完毕");
}finally {
stampedLock.unlockWrite(stamp);
}
}
public void read() throws InterruptedException {
long stamp = stampedLock.readLock();
System.out.println(Thread.currentThread().getName() + " 准备读,持续 4 s");
for (int i = 0; i < 4; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() +" 正在读………………");
}
try{
int result = number;
System.out.println(Thread.currentThread().getName() + "获取成员变量" + result);
System.out.println("写操作没有修改成功,读锁时候写锁无法介入,传统读写互斥");
}finally {
stampedLock.unlockRead(stamp);
}
}
public static void main(String[] args) throws InterruptedException {
StampLockDemo stampLockDemo = new StampLockDemo();
new Thread(()->{
try {
stampLockDemo.read();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"readThread").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
System.out.println(Thread.currentThread().getName() + " come in");
stampLockDemo.write();
},"writeThread").start();
}
}

可以发现在读操作期间,写操作是没有执行的,所以和上面的 reentrantreadwritelock 目前是一致的,只是添加了戳记,其他都一样
尝试使用乐观锁去读:


缺点:
①、继承的父类不同:wait 父类为 Object,await 父类为 ConditionObject
②、wait 需要配合 synchronized 使用,await 不需要
③、await 阻塞需要使用 condition 对象
④、wait 阻塞需要使用 notify 唤醒,await 阻塞需要使用 signal
⑤、wait 一般适用于 synchronized 场景中,而 await 一般只适用于 reentrantlock 中