目录
1、使用AtomicInteger的原子自增
2、Synchronized + wait + notify
3、ReentrantLock + Condition
4、Semaphore
实现:三个线程循环打印ABC 1000次。
缺点:线程的run方法中有while循环,三个线程会频繁地进行线程切换,可能造成巨大的资源浪费。极端情况下,也有可能出现饥饿线程的场景。
public class MyThread implements Runnable{
private String out;
private AtomicInteger atomicInteger;
private static String[] chars = {"A", "B", "C"};
public MyThread(String out, AtomicInteger atomicInteger) {
this.out = out;
this.atomicInteger = atomicInteger;
}
@Override
public void run() {
// 循环打印ABC 1000次
while (atomicInteger.get() < 3 * 1000) {
if (out.equals(chars[atomicInteger.get() % 3])) {
System.out.println(out);
// 原子自增操作
atomicInteger.getAndIncrement();
}
}
}
}
public class Main {
/**
* 每个线程都处在while循环中,线程间切换可能造成巨大的资源浪费
* 极端情况下也有可能出现饥饿线程的场景
*/
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger();
Thread thread1 = new Thread(new MyThread("A", atomicInteger));
Thread thread2 = new Thread(new MyThread("B", atomicInteger));
Thread thread3 = new Thread(new MyThread("C", atomicInteger));
thread1.start();
thread2.start();
thread3.start();
}
}
实现:三个线程循环打印ABC 1000次。
缺点:相比于AtomicInteger方法,while中的wait方法虽然能阻塞当前线程,减少线程间的切换导致的开销。但是lock.notifyAll方法后,是唤醒所有的阻塞线程,使三个线程重新竞争lock对象锁;竞争是公平的,所以也会有线程抢到锁后,重新进入阻塞状态,仍旧会有大量无用的线程切换。
public class MyThread1 implements Runnable{
private String out;
private static Integer status = 0;
private static String[] chars = {"A", "B", "C"};
private static final Object lock = new Object();
public MyThread1(String out) {
this.out = out;
}
@SneakyThrows
@Override
public void run() {
// 打印A|B|C 1000次
for (int index = 0; index < 1000; index++) {
synchronized (lock) {
while (!out.equals(chars[status % 3])) {
lock.wait();
}
System.out.println(Thread.currentThread().getName() + ":" + out);
status++;
lock.notifyAll();
}
}
}
}
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(new MyThread1("A"), "线程1");
Thread thread2 = new Thread(new MyThread1("B"), "线程2");
Thread thread3 = new Thread(new MyThread1("C"), "线程3");
thread1.start();
thread2.start();
thread3.start();
}
}
实现:三个线程循环打印ABC 1000次。
通过三个Condition分别控制各个线程的休眠与唤醒。condition.await()休眠线程,condition.signal()唤醒线程。
public class MyThread2 implements Runnable{
private String out;
private static Integer status = 0;
private static String[] chars = {"A", "B", "C"};
private ReentrantLock lock;
private Condition current;
private Condition next;
public MyThread2(String out, ReentrantLock lock, Condition current, Condition next) {
this.out = out;
this.lock = lock;
this.current = current;
this.next = next;
}
@SneakyThrows
@Override
public void run() {
// 打印A|B|C 1000次
for (int index = 0; index < 1000; index++) {
lock.lock();
try {
while (!out.equals(chars[status % 3])) {
current.await();
}
System.out.println(Thread.currentThread().getName() + ":" + out);
status++;
next.signal();
} finally {
lock.unlock();
}
}
}
}
public class Main {
@SneakyThrows
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition A = lock.newCondition();
Condition B = lock.newCondition();
Condition C = lock.newCondition();
Thread thread1 = new Thread(new MyThread2("A", lock, A, B), "线程1");
Thread thread2 = new Thread(new MyThread2("B", lock, B, C), "线程2");
Thread thread3 = new Thread(new MyThread2("C", lock, C, A), "线程3");
thread1.start();
thread2.start();
thread3.start();
}
}
实现:三个线程循环打印ABC 1000次。
与Condition方式有点类似,通过三个信号量控制三个线程的阻塞与唤醒,semaphore.acquire()获取许可,信号量-1,当信号量为0时,阻塞;semaphore.release()释放许可,信号量+1。
public class MyThread3 implements Runnable{
private String out;
private Semaphore current;
private Semaphore next;
public MyThread3(String out, Semaphore current, Semaphore next) {
this.out = out;
this.current = current;
this.next = next;
}
@SneakyThrows
@Override
public void run() {
// 打印A|B|C 1000次
for (int index = 0; index < 1000; index++) {
// 获取许可,current信号量-1
current.acquire();
System.out.println(Thread.currentThread().getName() + ":" + out);
// 释放许可,next信号量+1
next.release();
}
}
}
public class Main {
@SneakyThrows
public static void main(String[] args) {
Semaphore A = new Semaphore(1);
Semaphore B = new Semaphore(0);
Semaphore C = new Semaphore(0);
Thread thread1 = new Thread(new MyThread3("A", A, B), "线程1");
Thread thread2 = new Thread(new MyThread3("B", B, C), "线程2");
Thread thread3 = new Thread(new MyThread3("C", C, A), "线程3");
thread1.start();
thread2.start();
thread3.start();
}
}
以上内容为个人学习理解,如有问题,欢迎在评论区指出。
部分内容截取自网络,如有侵权,联系作者删除。