用多线程顺序打印ABC多次?

问题描述:有三个线程顺序打印abc十次,请用线程同步实现。

1. synchronized锁 + 状态位

package com.fll.juc.interviews;

public class ThreadPrintABCSequential implements Runnable{

	/**
	 * 问题描述:
	 * 有三个线程顺序打印abc十次,请用线程同步实现。
	 */
	private final int PRINT_COUNT = 10;
	private static volatile int flag = 1; //这里必须要用static,不然打印的时候阻塞
	
	private Object thisLock; 
	private char value;
	
	
    public static void main(String[] args) throws InterruptedException {

		Object thisLock = new Object();
		
		new Thread(new ThreadPrintABCSequential(thisLock,'A')).start();
		new Thread(new ThreadPrintABCSequential(thisLock,'B')).start();
		new Thread(new ThreadPrintABCSequential(thisLock,'C')).start();

		Thread.sleep(100);
	
}
	
	/**
	 * @param thisLock 当前锁
	 * @param value 要打印的字符
	 */
	public ThreadPrintABCSequential(Object thisLock,char value) {
		this.thisLock = thisLock;
		this.value = value;
	}
	
	@Override
	public void run(){
		for (int i = 0; i < PRINT_COUNT; i++) {
			
			if(value == 'A') {		
				//如果是要打印A,则线程A能拿到锁之后,BC线程都暂停打印一个A
				synchronized(thisLock) {
					while(flag != 1) {
						try {
							thisLock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					System.out.println('A');
					flag = 2;
					thisLock.notifyAll(); //提醒A线程开始
				}
				
			}else if(value == 'B') {
				synchronized(thisLock) {
					while(flag != 2) {
						try {
							thisLock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					System.out.println('B');
					flag = 3;
					thisLock.notifyAll(); //提醒B线程开始
				}
			}else if (value == 'C') {
				synchronized(thisLock) {
					while(flag != 3) {
						try {
							thisLock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}	
					}
					System.out.println('C');	
					flag = 1;
					thisLock.notifyAll(); //提醒C线程开始
				}
			}
			
		}
	}
}

输出:

分析:flag用来标注下一个要打印的字符,如果是1,代表打印A;如果是2,代表打印B;如果是3,代表打印C;注意:flag必须要用static和volatile修饰

2. ReetrantLock + condition 其实思路和第一种类似

package com.fll.juc.interviews;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadPrintABCSequential_ReentrantLock implements Runnable{

	/**
	 * 问题描述:
	 * 有三个线程顺序打印abc十次,请用线程同步实现。
	 */
	private final int PRINT_COUNT = 10; //打印次数
	
	private static volatile int flag = 1; //这里必须要用static,不然打印的时候阻塞
	
	private Lock lock;  //锁对象
	
	private Condition condition; //condition对象,负责处理线程状态
	
	private char charValue; //打印字符
	
    public static void main(String[] args) throws InterruptedException {
    	
    	Lock lock = new ReentrantLock();
    	Condition conditionA = lock.newCondition();

    	ThreadPrintABCSequential_ReentrantLock tReentrantLockA = new ThreadPrintABCSequential_ReentrantLock(lock,conditionA,'A');
    	ThreadPrintABCSequential_ReentrantLock tReentrantLockB = new ThreadPrintABCSequential_ReentrantLock(lock,conditionA,'B');
    	ThreadPrintABCSequential_ReentrantLock tReentrantLockC = new ThreadPrintABCSequential_ReentrantLock(lock,conditionA,'C');
    	
    	//用线程池操作
    	ExecutorService pool = Executors.newFixedThreadPool(5); //创建一个默认线程数为5的线程池
    	pool.execute(tReentrantLockA);
    	pool.execute(tReentrantLockB);
    	pool.execute(tReentrantLockC);
    	
    	Thread.sleep(100);
    	
    	pool.shutdown();
    }
    
    @Override
    public void run() {
    	
    	try {
			lock.lock();
    		
			for (int i = 0; i < PRINT_COUNT; i++) {
				
	    		if(charValue == 'A') {		
    	    		while( flag != 1 ) {
    	    			condition.await();
    	    		}
    	    		System.out.println(""+(i+1)+":"+charValue);
    	    		flag=2;
    	    		condition.signal();
	    	    
	    		}else if(charValue == 'B') {

    	    		while( flag != 2 ) {
    	    			condition.await();
    	    		}
    	    		System.out.println(""+(i+1)+":"+charValue);
    	    		flag=3;
    	    		condition.signal();
	    	    			    
	    		}else if(charValue == 'C') {

    	    		while( flag != 3 ) {
    	    			condition.await();
    	    		}
    	    		System.out.println(""+(i+1)+":"+charValue);
    	    		flag=1;
    	    		condition.signal();

	    		}
			}
    		
		}catch(Exception e){
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
    	
	}
    
    public ThreadPrintABCSequential_ReentrantLock(Lock thisLock,Condition condition,char value){
    	this.lock = thisLock;
    	this.charValue = value;
    	this.condition = condition;
    }
}

输出:

需要注意的是显示锁ReentrantLock需要用在try finally块内,最后必须释放锁。

try {
  lock.lock();
  //...
}catch(Exception e){
  e.printStackTrace();
} finally {
  lock.unlock();
}
posted @ 2021-03-02 09:35  方罗良  阅读(440)  评论(0)    收藏  举报