1. 题目:
给3个线程分别交替打印A、B、C,10次,
预期结果为:
thread1: A
thread2: B
thread3: C
thread1: A
thread2: B
thread3: C
thread1: A
thread2: B
thread3: C
...
2. 解法
2.1 使用synchronized
思路:
- 使用synchronized给某个对象上锁
- 线程的打印顺序使用一个变量n%3来控制,0 代表线程打印A, 1代表线程打印B, 2代表线程打C
- 打印完后,通知其他线程解锁
public void solutionBySync(){
SyncObject syncObject = new SyncObject();
new SyncThread(syncObject,"A").start();
new SyncThread(syncObject,"B").start();
new SyncThread(syncObject,"C").start();
}
class SyncObject{
}
private int num = 0;
class SyncThread extends Thread{
private SyncObject sync;
private String name;
private String[] arr = {"A","B","C"};
public SyncThread(SyncObject syncObject,String name){
this.sync = syncObject;
this.name = name;
}
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
synchronized (sync){
if(name.equals(arr[num%3])){
System.out.println(name);
num ++;
sync.notifyAll();
}else{
try {
sync.wait();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
}
2.2 通过CAS
思路:
- 使用cas 在while中自旋等待获取锁
- 线程的打印顺序使用一个变量n%3来控制,0 代表线程打印A, 1代表线程打印B, 2代表线程打C
- 打印完后,brerk 当前while,进入下一轮打印
public void solutionByCAS(){
AtomicInteger num = new AtomicInteger(0);
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new CASThread("A",num));
executorService.submit(new CASThread("B",num));
executorService.submit(new CASThread("C",num));
executorService.shutdown();
}
class CASThread implements Runnable{
private String name;
private AtomicInteger num;
public CASThread(String name, AtomicInteger num){
this.name = name;
this.num = num;
}
private String[] arr = {"A","B","C"};
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
while(true){
if(name.equals(arr[num.get()%3])){
System.out.println(name);
num.getAndIncrement();
break;
}
}
}
System.out.println("over:"+name);
}
}
2.3 使用Semaphore
思路:
- 设置3个信号量,其中打印a的信号量初识值设置为1
- 打印a的线程,先消耗掉1个信号量后开始打印A,然后给打印b的信号量释放1个量
- 打印b的线程,先消耗掉1个信号量后开始打印B,然后给打印C的信号量释放1个量
- 打印c的线程,先消耗掉1个信号量后开始打印C,然后给打印A的信号量释放1个量
- 周而复始,打印10遍
public void solutionBySemaphore(){
Semaphore sa = new Semaphore(1);
Semaphore sb = new Semaphore(0);
Semaphore sc = new Semaphore(0);
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
try {
sa.acquire(1);
System.out.println("A");
sb.release(1);
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
try {
sb.acquire(1);
System.out.println("B");
sc.release(1);
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
try {
sc.acquire(1);
System.out.println("C");
sa.release(1);
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
}
}).start();
}
2.4 使用ReentrantLock
思路:
- 对一个可重入锁设置3个条件
- 线程的打印顺序使用一个变量k来控制,0 代表线程打印A, 1代表线程打印B, 2代表线程打C
- 打印线程你如后如果还轮不到自己打印那么就await();等待其他线程唤醒signal();
- 打印a的线程 唤醒 打印b的线程,打印b的线程 唤醒 打印c的线程,打印c的线程 唤醒 打印a的线程
- 周而复始,打印10次
private int k = 1;
public void solutionByLock() {
ReentrantLock lock = new ReentrantLock();
Condition ca = lock.newCondition();
Condition cb = lock.newCondition();
Condition cc = lock.newCondition();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
lock.lock();
try {
if(k != 1){
ca.await();
}
System.out.println("A");
k=2;
cb.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
lock.lock();
try {
if(k!=2){
cb.await();
}
System.out.println("B");
k=3;
cc.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
lock.lock();
try {
if(k!=3){
cc.await();
}
System.out.println("C");
k=1;
ca.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}).start();
}