Java多线程循环打印ABC的5种实现方法

题目:3个线程循环打印ABC,其中A打印3次,B打印2次,C打印1次,循环打印2轮

一.Synchronized同步法

思路:使用synchronized、wait、notifyAll的方法利用线程标记变量控制三个线程的执行顺序。

/**
 * @author XDarker
 * 2018-5-17
 */
public class Main {
	
	public static void main(String[] args) throws InterruptedException {
		
		int num = 1;//当前正在执行线程的标记
		ABCPrint print = new ABCPrint(num); 
		
		Thread threadA = new Thread(new RunnableA(print));
		Thread threadB = new Thread(new RunnableB(print));
		Thread threadC = new Thread(new RunnableC(print));
		threadA.start();
		Thread.sleep(500);
		threadB.start();
		Thread.sleep(500);
		threadC.start();
	}
}
class RunnableA implements Runnable{
	
	private ABCPrint print;
	public RunnableA(ABCPrint print) {
		super();
		this.print = print;	
	}

	@Override
	public void run() {		
		print.PrintA();
		
	}
}
class RunnableB implements Runnable{
	
	private ABCPrint print;
	public RunnableB(ABCPrint print) {
		super();
		this.print = print;
	}

	@Override
	public void run() {		
		print.PrintB();
	}
}
class RunnableC implements Runnable{
	
	private ABCPrint print;
	public RunnableC(ABCPrint print) {
		super();
		this.print = print;
	}

	@Override
	public void run() {		
		print.PrintC();
	}
}
class ABCPrint {

	private int num;//当前正在执行线程的标记
	public ABCPrint(int num) {
		super();
		this.num = num;
	}
	
	
	public void PrintA(){
		for (int j = 0; j < 2; j++)//表示 循环打印2轮
		synchronized(this){
	              while(num != 1){
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			for (int i = 0; i < 3; i++) {//表示 打印3次
				System.out.println("A");  
			}
			
		    //打印A线程执行完 ,通知打印B线程
                    num = 2;  
                    this.notifyAll();  
	        }
	}
	
	public void PrintB(){
		for (int j = 0; j < 2; j++)//表示 循环打印2轮
		synchronized(this){
			while(num != 2){
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			for (int i = 0; i < 2; i++) {//表示 打印2次
				System.out.println("B");  
			}
		    //打印B线程执行完 ,通知打印C线程
                    num = 3;  
                    this.notifyAll();  
		}
	}
	
	public void PrintC(){
		for (int j = 0; j < 2; j++)//表示 循环打印2轮
		synchronized(this){
			while(num != 3){
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
	            System.out.println("C");  
	            //打印C线程执行完 ,通知打印A线程
                    num = 1;  
                    this.notifyAll();  
		}
	}	
}	

二.Lock锁方法

思路:Lock锁机制是JDK 5之后新增的锁机制,不同于内置锁,Lock锁必须显式声明,并在合适的位置释放锁。Lock是一个接口,通过ReentrantLock具体实现进行显式的锁操作,即获取锁和释放锁。

/**
 * @author XDarker
 * 2018-5-17
 */
public class Main {
	
	public static void main(String[] args) throws InterruptedException {
		
		int  num = 1;//当前正在执行线程的标记
		ABCPrint print = new ABCPrint(num); 
		
		Thread threadA = new Thread(new RunnableA(print));
		Thread threadB = new Thread(new RunnableB(print));
		Thread threadC = new Thread(new RunnableC(print));
		threadA.start();
		Thread.sleep(500);
		threadB.start();
		Thread.sleep(500);
		threadC.start();
	}
}
class RunnableA implements Runnable{
	
	private ABCPrint print;
	public RunnableA(ABCPrint print) {
		super();
		this.print = print;	
	}

	@Override
	public void run() {		
		print.PrintA();
		
	}
}
class RunnableB implements Runnable{
	
	private ABCPrint print;
	public RunnableB(ABCPrint print) {
		super();
		this.print = print;
	}

	@Override
	public void run() {		
		print.PrintB();
	}
}
class RunnableC implements Runnable{
	
	private ABCPrint print;
	public RunnableC(ABCPrint print) {
		super();
		this.print = print;
	}

	@Override
	public void run() {		
		print.PrintC();
	}
}
class ABCPrint {
	private static final Lock lock = new ReentrantLock();//通过JDK5中的Lock锁来保证线程的访问的互斥
	
	private int num;//当前正在执行线程的标记
	public ABCPrint(int num) {
		super();
		this.num = num;
	}
	
	
	public void PrintA(){
		for (int j = 0; j < 2;)//表示 循环打印2轮
			try {
			    lock.lock();
			    while(num == 1){
				for (int i = 0; i < 3; i++) {//表示 打印3次
				    System.out.println("A");  
		        	}
			       //打印A线程执行完 ,通知打印B线程
		                num = 2;  
		                j++;
			    }
			}finally{//调用了lock方法后,需在finally(finally确保一定会执行,除非执行了exit方法)语句里调用unlock方法。否则会造成死锁等问题
			    lock.unlock();
			}
	}  
	
	public void PrintB(){
		for (int j = 0; j < 2;)//表示 循环打印2轮
		       try{
		            lock.lock();
			    while(num == 2){
				for (int i = 0; i < 2; i++) {//表示 打印2次
					System.out.println("B");  
				}
			        //打印B线程执行完 ,通知打印C线程
	                        num = 3;  
	                        j++;	    
		        }finally{
			    lock.unlock();
		        }	
	}
	
	public void PrintC(){
		for (int j = 0; j < 2;)//表示 循环打印2轮
			try{
			    lock.lock();
			    while(num == 3){
			       System.out.println("C"); 
			       //打印C线程执行完 ,通知打印A线程
		               num = 1;  
		               j++;
	                    }  
			}finally{
			    lock.unlock();
			}
	}
	
}	

三.ReentrantLock结合Condition

思路:Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法。Condition它更强大的地方在于:能够更加精细的控制多线程的休眠与唤醒。对于同一个锁,我们可以创建多个Condition,在不同的情况下使用不同的Condition。

/**
 * @author XDarker
 * 2018-5-17
 */
public class Main{

	public static void main(String[] args) {
		
		final AlternateDemo ad = new AlternateDemo();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 0; i < 2; i++) {
					ad.loopA(i);
				}
				
			}
		},"A").start();
		
		new Thread(new Runnable() {
					
					@Override
					public void run() {
						for (int i = 0; i < 2; i++) {
							ad.loopB(i);
						}
						
					}
				},"B").start();

		new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 0; i < 2; i++) {
					ad.loopC(i);
				}
			}
		},"C").start();
		
	}
	
}

class AlternateDemo{
	
	private int num = 1;//当前正在执行线程的标记
	
	private Lock lock =  new ReentrantLock();
	
	private Condition condition1 = lock.newCondition();
	private Condition condition2 = lock.newCondition();
	private Condition condition3 = lock.newCondition();
	
	public void loopA(int loop){
		
		lock.lock();
		
		try {
			//1.判断
			if(num != 1){
				condition1.await();
			}
			
			//2.打印
			for (int i = 0; i < 3; i++) {
				System.out.println(Thread.currentThread().getName()+"-"+"第"+loop+"轮"+"-第"+i+"次");
			}
			
			//3.唤醒
			num = 2;
			condition2.signal();
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}
	}
	
	public void loopB(int loop){
		
		lock.lock();
		
		try {
			//1.判断
			if(num != 2){
				condition2.await();
			}
			
			//2.打印
			for (int i = 0; i < 2; i++) {
				System.out.println(Thread.currentThread().getName()+"-"+"第"+loop+"轮"+"-第"+i+"次");
			}
			
			//3.唤醒
			num = 3;
			condition3.signal();
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}
	}

	public void loopC(int loop){
	
	lock.lock();
		
		try {
			//1.判断
			if(num != 3){
				condition3.await();
			}
			
			//2.打印
			for (int i = 0; i < 1; i++) {
				System.out.println(Thread.currentThread().getName()+"-"+"第"+loop+"轮"+"-第"+i+"次");
			}
			System.out.println("---------------------------");
			//3.唤醒
			num = 1;
			condition1.signal();
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}
	}
}

四.AtomicInteger方法

思路:AtomicInteger,一个提供原子操作的Integer的类。在Java中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。

/**
 * @author XDarker
 * 2018-5-17
 */
public class Main {

	public static void main(String[] args) {
		new ABCPrint("A",3).start();//A打印3次
		new ABCPrint("B",2).start();//B打印2次
		new ABCPrint("C",1).start();//C打印1次
	}
	
}

class ABCPrint extends Thread {
	
	//打印次数
	private int count;

	private final String str[] = { "A", "B", "C" };
	private final static AtomicInteger  atomCount= new AtomicInteger();

	public ABCPrint(String name,int count) {
		this.setName(name);
		this.count = count;
	}

	@Override
	public void run() {
		while (true) {
			// 循环满2轮退出打印
			if (atomCount.get() / 3 == 2) {
				break;
			}
			synchronized (atomCount) {
				// 顺序打印A、B、C
				if (str[atomCount.get() % 3].equals(getName())) {
					atomCount.getAndIncrement();//自增
					
					//对应打印几次 
					for (int i = 0; i < count; i++) {
						System.out.println(getName());
					}
					
					//表示一轮打印结束 方便观察打印下分隔符
					if ("C".equals(getName())) {
						System.out.println("================================");
					}
					// 当前线程打印打印完成后唤醒其它线程
					atomCount.notifyAll();
				} else {
				// 非顺序线程wait()
					try {
						atomCount.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

}	

五.Semaphore信号量方式

思路: 信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。Semaphore线程同步机制,当调用acquire()时,内部计数器数值增加;调用release()时,内部计数器递减;计数器值不能小于0,如果等于0,acquire()方法被阻塞,需要等待其他线程调用release()方法。

/**
 * @author XDarker
 * 2018-5-17
 */
public class Main {
	
	 public static void main(String[] args) throws InterruptedException {
	        new ThreadA(3).start();
	        new ThreadB(2).start();
	        new ThreadC(1).start();
	   }
	 
	//以A开始的信号量,初始信号量数量为1
    private static Semaphore A = new Semaphore(1);
    //B、C信号量,A完成后开始,初始信号数量为0
    private static Semaphore B = new Semaphore(0);
    private static Semaphore C = new Semaphore(0);


    static class ThreadA extends Thread {
    	private int count;
        public ThreadA(int count) {
			super();
			this.count = count;
		}
		@Override
        public void run() {
            try {
                for (int i = 0; i < 2; i++) {
                    A.acquire();// A获取信号执行,A信号量减1,当A为0时将无法继续获得该信号量
                    for (int j = 0; j < count; j++) {
                    	   System.out.print("A");
					}
                 
                    B.release();// B释放信号,B信号量加1(初始为0),此时可以获取B信号量
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    static class ThreadB extends Thread {
    	private int count;
        public ThreadB(int count) {
			super();
			this.count = count;
		}
        @Override
        public void run() {
            try {
                for (int i = 0; i < 2; i++) {
                    B.acquire();
                    for (int j = 0; j < count; j++) {
                    	System.out.print("B");
					}
                    C.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    static class ThreadC extends Thread {
    	private int count;
        public ThreadC(int count) {
			super();
			this.count = count;
		}
        @Override
        public void run() {
            try {
                for (int i = 0; i < 2; i++) {
                    C.acquire();
                    for (int j = 0; j < count; j++) {
                    	System.out.println("C");
					}
                    A.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
   
}

 

  • 25
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java多线程每个线程挨着打印abc的4实现方式如下: 1. 使用同步方法: 在一个类中创建一个共享的锁对象。创建3个线程,分别调用该对象的3个同步方法,在每个方法中使用循环打印对应的字符,然后调用notifyAll()方法唤醒其他两个线程,最后调用wait()方法当前线程进入等待状态。 2. 使用synchronized关键字: 在一个类中创建一个共享的锁对象,并使用synchronized关键字修饰方法。创建3个线程,分别调用该对象的3个同步方法,在每个方法中使用循环打印对应的字符,然后调用notifyAll()方法唤醒其他两个线程,最后调用wait()方法当前线程进入等待状态。 3. 使用Lock和Condition接口: 创建一个ReentrantLock对象和3个Condition对象。创建3个线程,分别获取对应的Condition对象,然后在循环中使用Lock对象的lock()方法获取锁,使用对应的Condition对象的await()方法等待,直到该线程被唤醒后打印对应的字符,并调用其他两个Condition对象的signalAll()方法唤醒其他两个线程。 4. 使用信号量Semaphore: 创建一个Semaphore对象和3个线程。在每个线程中使用Semaphore对象的acquire()方法获取许可,然后在循环打印对应的字符,最后调用Semaphore对象的release()方法释放许可,并通知其他两个线程获取许可。 以上这四方式都可以实现多线程每个线程挨着打印abc的效果。然而,具体的选择取决于实际情况,例如需要考虑线程的数量、同步机制的复杂度、线程间协作的方式等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值