线程安全的单例模式
双重检查锁定
java
// 线程安全的单例模式:双重检查锁定
public class Singleton {
// volatile防止指令重排序 instance = new Singleton()
// 1.分配内存空间 2.初始化对象 3.引用赋值给instance
// 如重排为1-3-2,则可能将尚未完成初始化的对象引用暴露给其他线程访问
private static volatile Singleton instance;
// 私有化构造方法,不允许外部实例化
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) { // 避免不必要的加锁同步,已存在实例
// 一个线程获取锁进入,其他线程在此等待释放锁
synchronized (Singleton.class) {
if (instance == null) { // 确保实例唯一,已存在实例
instance = new Singleton();
}
}
}
return instance;
}
}
线程循环打印
三个线程循环打印,线程一打印A,线程二打印B,线程三打印C,打印10遍
采用synchronized + wait/notify/notifyAll
java
// 三个线程循环打印A B C
public class PrintABC {
// volatile保证可见性:每次读从主内存拿最新值,每次写立刻刷回主内存,不加锁开销小
// **但i++这种复合操作无法保护,两个线程可能同时读到同一个值,加1后写回
// private volatile int flag = 0;
// 标志位 0-A 1-B 2-C
// synchronized块内部读写时,进入同步块清空本地缓存,退出时刷新主内存,已经保证可见性
private int flag = 0;
// 同一个监视器对象,保证互斥
private final Object lock = new Object();
public void print(int turn, char ch) { // 谁执行
// 同步块
synchronized (lock) {
while (flag != turn) {
try {
lock.wait(); // 不是当前线程执行时机 释放锁等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 执行
System.out.println(ch);
// 修改标志位
flag = (flag + 1) % 3;
// 释放锁,唤醒其他线程
lock.notifyAll();
}
}
public static void main(String[] args) {
PrintABC printABC = new PrintABC();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
printABC.print(0, 'A');
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
printABC.print(1, 'B');
}
});
Thread thread3 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
printABC.print(2, 'C');
}
});
thread1.start();
thread2.start();
thread3.start();
}
}
采用ReetrantLock + Condition
java
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class PrintABC1 {
private int flag = 0;
private final ReentrantLock lock = new ReentrantLock();
private final Condition conditionA = lock.newCondition();
private final Condition conditionB = lock.newCondition();
private final Condition conditionC = lock.newCondition();
// 谁执行 唤醒谁
public void print(int turn, char ch, Condition cs, Condition ce) {
// 加锁
lock.lock();
try {
while (flag != turn) {
// 不满足cs执行时机 释放锁进入等待
cs.await();
}
// 执行
System.out.println(ch);
// 修改标志位
flag = (flag + 1) % 3;
// 精确唤醒ce
ce.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 手动释放锁
lock.unlock();
}
}
public static void main(String[] args) {
PrintABC1 pt = new PrintABC1();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
pt.print(0, 'A', pt.conditionA, pt.conditionB);
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
pt.print(1, 'B', pt.conditionB, pt.conditionC);
}
});
Thread thread3 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
pt.print(2, 'C', pt.conditionC, pt.conditionA);
}
});
thread1.start();
thread2.start();
thread3.start();
}
}
保证线程顺序执行
保证线程T1,T2,T3按顺序执行
采用JOIN串行启动
java
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> System.out.println("th1"));
Thread t2 = new Thread(() -> System.out.println("th2"));
Thread t3 = new Thread(() -> System.out.println("th3"));
t1.start();
// 让当前main线程阻塞,直到t1线程执行完毕才启动t2线程
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
}
}
采用CountDownLatch
java
import java.util.concurrent.CountDownLatch;
public class CdLatch {
public static void main(String[] args) {
// 两个门闩
CountDownLatch c1 = new CountDownLatch(1); // t1-t2
CountDownLatch c2 = new CountDownLatch(1); // t2-t3
Thread t1 = new Thread(() -> {
System.out.println("thread1");
c1.countDown(); // t1执行完后c1计数器减一
});
Thread t2 = new Thread(() -> {
try {
c1.await(); // t2需要c1计数器为零才能执行 否则等待
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread2");
c2.countDown(); // t2执行完后c2计数器减一
});
Thread t3 = new Thread(() -> {
try {
c2.await(); // t3需要c2计数器为零才能执行 否则等待
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread3");
});
t1.start();
t2.start();
t3.start();
}
}
采用CompletableFuture
java
import java.util.concurrent.CompletableFuture;
public class cptFuture {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println("thread1");
});
Thread t2 = new Thread(() -> {
System.out.println("thread2");
});
Thread t3 = new Thread(() -> {
System.out.println("thread3");
});
// 函数式风格
CompletableFuture<Void> future = CompletableFuture
.runAsync(t1)
.thenRun(t2)
.thenRun(t3); // t1->t2->t3
}
}
采用单个线程的线程池
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Executor {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> System.out.println("th1"));
executor.submit(() -> System.out.println("th2"));
executor.submit(() -> System.out.println("th3"));
executor.shutdown();
}
}
生产者消费者
直接使用阻塞队列BlockingQueue
java
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class pdCuQueue {
private static final int MAX_QUEUE_SIZE = 2;
// 队满插入阻塞,队空取数据阻塞
private static final LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(MAX_QUEUE_SIZE);
private static final AtomicInteger Product = new AtomicInteger(1);
public static void main(String[] args) {
for (int i = 1; i <= 2; i++) {
new Thread(new Producer(i)).start();
}
for (int i = 1; i <= 5; i++) {
new Thread(new Consumer(i)).start();
}
}
private static class Producer implements Runnable {
private int id;
public Producer(int id) {
this.id = id;
}
@Override
public void run() {
while (Product.get() <= 20) { // 生产暂停
int num = Product.getAndIncrement();
try {
Thread.sleep(1000);
System.out.println("Producer " + id + " Produces " + num);
queue.put(num);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
break;
}
}
}
}
private static class Consumer implements Runnable {
private int id;
public Consumer(int id) {
this.id = id;
}
@Override
public void run() {
while (true) {
try {
Integer num = queue.poll(5, TimeUnit.SECONDS); // 超时 避免永久阻塞
if (num == null && queue.isEmpty()) {
break;
}
System.out.println("Consumer " + id + " consume " + num);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
break;
}
}
}
}
}
采用 synchronized + wait/notify/notifyAll + Queue
java
import java.util.ArrayDeque;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
public class selfQueue {
public final static int MAX_QUEUE_SIZE = 2;
public final static AtomicInteger ATOMIC_INTEGER = new AtomicInteger(0);
public static volatile boolean productionDone = false;
private static class Consumer implements Runnable {
private ArrayDeque<Integer> queue;
private int ID;
public Consumer(ArrayDeque<Integer> queue, int ID) {
this.queue = queue;
this.ID = ID;
}
@Override
public void run() {
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
if (productionDone) {
return; // 已经生产结束,不在等待消费
}
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int num = queue.poll();
System.out.println("Consumer " + ID + " consume " + num);
queue.notifyAll();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private static class Producer implements Runnable {
private ArrayDeque<Integer> queue;
private int ID;
private Random random;
public Producer(ArrayDeque<Integer> queue, int ID) {
this.queue = queue;
this.ID = ID;
random = new Random();
}
@Override
public void run() {
while (true) {
synchronized (queue) {
if (ATOMIC_INTEGER.get() >= 20) break; // 进入前判断
while (queue.size() == MAX_QUEUE_SIZE) {
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (ATOMIC_INTEGER.get() >= 20) break; // 唤醒后判断
int num = random.nextInt(1000) + 1;
queue.offer(num);
ATOMIC_INTEGER.getAndIncrement();
System.out.println("Producer " + ID + " produce " + num);
queue.notifyAll();
}
try {
// sleep会占用锁,放在同步块外面
Thread.sleep(random.nextInt(1000) + 1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
productionDone = true; // 生产完成
synchronized (queue) {
queue.notifyAll(); // 唤醒可能正在等待空队列的消费者
}
}
}
public static void main(String[] args) {
ArrayDeque<Integer> queue = new ArrayDeque<>(MAX_QUEUE_SIZE);
for (int i = 1; i <= 2; i++) {
new Thread(new Producer(queue, i)).start();
}
for (int i = 3; i <= 6; i++) {
new Thread(new Consumer(queue, i)).start();
}
}
}
死锁
java
public class deadLock {
private final static Object lockA = new Object();
private final static Object lockB = new Object();
// 互斥
// 持有并等待
// 不可剥夺
// 循环等待
public static void main(String[] args) {
new Thread(() -> {
synchronized (lockA) {
try {
Thread.sleep(1000); // 让另一个线程先把B锁拿到
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB) { // 持有A还想持有B
System.out.println("A -> B");
}
}
}).start();
new Thread(() -> {
synchronized (lockB) {
try {
Thread.sleep(1000); // 让另一个线程先把A锁拿到
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockA) { // 持有B还想持有A
System.out.println("B -> A");
}
}
}).start();
}
}
线程安全的计数累加
100个线程分别累加100次,最终结果为10000
采用原子类
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class secureAdd {
// 底层CAS竞争同一value,CAS失败就重试
private static final AtomicInteger count = new AtomicInteger(0);
// private static volatile int count = 0;
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(100);
for (int i = 0; i < 100; i++) {
executor.submit(() -> {
for (int j = 0; j < 100; j++) {
count.incrementAndGet();
// count++;
}
});
} // 100个线程分别累加100次
executor.shutdown();
try {
// 等待所有任务执行完毕
executor.awaitTermination(1, TimeUnit.HOURS);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count.get());
// System.out.println(count);
}
}
采用累加器
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
public class secureAdd1 {
// 底层base+cell,先CAS尝试更新base,失败了则找到对应Cell更新,Cell之间互不干扰
// 求和时将base和Cell值加起来
// Cell数组触发扩容时容量翻倍但不超过核心CPU数
private final static LongAdder counter = new LongAdder();
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(100);
for (int i = 0; i < 100; i++) {
executor.submit(() -> {
for (int j = 0; j < 100; j++) {
counter.increment();
}
});
}
executor.shutdown();
try {
executor.awaitTermination(1, TimeUnit.HOURS);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(counter.sum());
}
}
模拟购票系统
总共100张票,10个窗口共同出售
采用synchronized + wait/notifyAll
java
public class TkService {
// 当前剩余票数 共享资源ticket
private static int ticket = 100;
// 同一个监视器对象
private static final Object lock = new Object();
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
new Thread(new ticketSeller(i)).start();
}
}
private static class ticketSeller implements Runnable {
// 窗口号
private final int windowNumber;
public ticketSeller(int windowNumber) {
this.windowNumber = windowNumber;
}
@Override
public void run() {
while (true) {
synchronized (lock) {
if (ticket > 0) { // 还有余票
buyTicket(); // 卖出
lock.notifyAll(); // 唤醒其他线程
try {
lock.wait(); // 释放锁 等待 不再执行后续代码
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
lock.notifyAll(); // 唤醒其他等待的线程 触发校验后都结束循环
break; // 没有余票结束循环
}
}
}
}
private void buyTicket() {
System.out.println("窗口 " + windowNumber + " 购买了一张票 " + " 还剩下 " + --ticket + " 张票");
}
}
}
采用Semaphore
java
import java.util.concurrent.Semaphore;
public class SpDemo {
private static int ticket = 100;
// Semaphore计数信号量,控制同时访问某个资源的线程数量
// new Semaphore(1,true) 许可数为1(实现synchronized的效果) + 公平模式(FIFO队列)
private static final Semaphore semaphore = new Semaphore(1);
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
new Thread(new ticketSeller(i)).start();
}
}
private static class ticketSeller implements Runnable {
private int windowNumber;
public ticketSeller(int windowNumber) {
this.windowNumber = windowNumber;
}
@Override
public void run() {
while (true) {
try {
// 调用acquire,若计数器大于0,则减一,继续执行;否则阻塞等待
semaphore.acquire();
if (ticket > 0) {
buyTicket();
} else {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 完成任务后调用release,计数器加1,唤醒一个等待的线程
semaphore.release();
}
}
}
private void buyTicket() {
System.out.println("窗口 " + windowNumber + " 卖出了一张票,还剩下 " + --ticket + " 张票");
}
}
}
线程池
java
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPoolDemo {
// 原子类
private static final AtomicInteger ID = new AtomicInteger(1);
public static void main(String[] args) {
// 线程池参数
int corePoolSize = 2;
int maxPoolSize = 5;
long keepAliveTime = 1L;
int queueCapacity = 10;
ThreadFactory tf = (r) -> new Thread(r, "thread-" + ID.getAndIncrement());
ThreadPoolExecutor executor = new ThreadPoolExecutor(
// 核心线程不够用,创建新线程
corePoolSize,
// 队列满,创建非核心线程,最多创建到最大线程数
maxPoolSize,
// 非核心线程空闲超时,回收多余线程
keepAliveTime,
// 空线超时的时间单位
TimeUnit.SECONDS,
// 核心线程数满,新任务在工作队列排队
// ArrayBlockingQueue LinkedBlockingQueue PriorityBlockingQueue DelayQueue SynchronousQueue
new ArrayBlockingQueue<>(queueCapacity),
// 线程工厂,自定义线程名
tf,
// 队列满且达到最大线程数,触发拒绝策略
// AbortPolicy CallerRunsPolicy DiscardOldestPolicy DiscardPolicy
new ThreadPoolExecutor.CallerRunsPolicy()
);
for (int i = 0; i < 100; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println(Thread.currentThread().getName() + " 执行任务 " + taskId);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
}
}
ThreadLocal实践
获取当前线程用户ID
java
package com.juc.threadlocal;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class thLocalDemo {
public static final AtomicInteger atomicInteger = new AtomicInteger(0);
// ThreadLocal线程隔离,每个线程都有自己独立的变量副本,不需要加锁也不会有竞争
// 每个Thread对象内部有一个threadLocals字段,类型是ThreadLocalMap,调用get时候先拿到该Map,再用ThreadLocal对象自身作为key去查
// ThreadLocalMap中Entry对key使用弱引用
// Entry<Key,Value> Key->ThreadLocal弱引用,如果栈上对ThreadLocal的强引用没了,下次GC就可以回收
// 声明static final,一个ThreadLocal实例对应一个线程变量即可
// withInitial设置默认值,防止get拿到null
private static final ThreadLocal<Integer> USER_ID = ThreadLocal.withInitial(() -> 0);
public static void handleRequest(int userId) {
try {
// 需要隔离的数据 该线程内整个调用链都可以获取到
USER_ID.set(userId);
System.out.println("Current User ID is: " + USER_ID.get());
} finally {
// 业务逻辑执行完必须remove 防止内存泄露和脏数据
USER_ID.remove();
}
}
public static class Request implements Runnable {
private final int userId;
public Request(int userId) {
this.userId = userId;
}
@Override
public void run() {
handleRequest(userId);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executor.submit(new Request(atomicInteger.getAndIncrement()));
}
executor.shutdown();
try {
executor.awaitTermination(1, TimeUnit.HOURS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}