java多线程中两个线程交替运行,分别输出奇偶数

本文介绍了如何在Java中实现两个线程交替执行,一个输出奇数,一个输出偶数。分别使用synchronized关键字、自旋锁、LockSupport工具类以及Lock和Condition接口的方法,详细阐述了各自的实现原理和特点。同时,文章还扩展讨论了如何编写程序,让3个线程按照特定顺序(A-B-C)交替打印。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:java中两个线程交替执行,一个输出奇数,一个输出偶数

方法一:
看到题目时,我第一个想到的是用synchronized加锁,然后使用notify唤醒线程和wait阻塞线程
通过 synchronized 锁定对象,每次只能有一个线程进入,每打印一个数,就释放锁,另一个线程进入,拿到锁,打印,唤醒另一个线程,然后挂起自己。循环反复,实现了一个最基本的打印功能。

public class Text1 {
	   private static int state=1;
	public static void main(String[] args) {
		final Text1 text1=new Text1();
	
		new Thread(new Runnable() {
			public void run() {
				synchronized (text1) {
					while(state!=1){//当state!=1是,说明不该线程1打印,则将线程1挂起,让线程2执行打印
						try {
							text1.wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}	
					
					for(int i=1;i<=100;i=i+2){
						System.out.println(i);//当线程1打印之后,该线程2打印了,此时将状态state置为2
						state=2;             //唤醒线程2,并使用wait交出锁资源,线程2执行打印
						try {
							text1.notify();
							text1.wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					//text1.notify();
				}
				
			}
		
	}).start();
		
		new Thread(new Runnable() {
			public void run() {
				synchronized (text1) {	
					while(state!=2){//当state!=2,说明不该线程2执行,则将线程2挂起,让线程1执行打印
						try {
							text1.wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					
				for(int i=2;i<=100;i=i+2){
					System.out.println(i);//线程2打印完成之后将state置为1,将线程1唤醒,并使用wait交出锁
					state=1;
					try {
						text1.notify();
						text1.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				text1.notify();
			}
		}
	}).start();
		
	}
}

方法二:
自旋锁的方式,就是我们没有用锁,相当于自己写了一个自旋锁,利用CAS原理

  public class Text1 {
	static  volatile int state=1;
	public static void main(String[] args) {
		
		new Thread(new Runnable() {
			public void run() {
				for(int i=1;i<=100;i=i+2){
					while(state!=1){//当state!=1时,说明此时不该线程1打印,则陷入循环等待线程2将state改为1后立即执行打印
					}
					System.out.println(i);
					state=2;
				}
				
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				for(int i=2;i<=100;i=i+2){
					while(state!=2){//当state!=2时,说明此时不该线程2打印,则陷入循环等待线程1执行完打印之后将state该为2(volatial可见性),再执行打印
						
					}
					System.out.println(i);
					state=1;
				}
				
			}
		}).start();
		
	}
}

方法三:
使用LockSupport,LockSupport是一个比较底层的工具类,用来创建锁和其他底层工具类的基本线程阻塞原语
LockSupport的特点:

  1. 不需要synchronized加锁就可以实现线程阻塞和唤醒。

  2. LockSupport的unpark()可以先与park()运行,并且线程不会阻塞。
    unpark() 唤醒线程 park() 阻塞线程

  3. 如果一个线程处于等待状态,连续调用了两次park()方法,就会是线程永远无法被唤醒

public class Text1 {
	   static Thread t1=null;
	   static Thread t2=null;
	public static void main(String[] args) { 
		 t1=new Thread(new Runnable() {
			public void run() {
				for(int i=1;i<=100;i=i+2){
					System.out.println(i);
					LockSupport.unpark(t2);//t1打印完唤醒t2
					LockSupport.park();//t1阻塞
					
				}
				
			}
		},"t1");
		
		t2=new Thread(new Runnable() {
			public void run() {
				for(int i=2;i<=100;i=i+2){
					LockSupport.park(); //阻塞t2
					System.out.println(i);
					LockSupport.unpark(t1);
			   }
			}
		},"t2");
		
		t1.start();
		t2.start();
	}

}

方法四:
使用Lock和Condition类来完成,Condition是Java提供了来实现等待/通知的类,Condition对象是由lock对象所创建的,但是同一个锁可以创建多个Condition的对象,即创建多个对象监视器。这样的好处就是可以指定唤醒线程。notify或notifyALL唤醒的线程是随机唤醒一个。

public class Text1 {
	  static Lock lock=new ReentrantLock();
	  static Condition conditionT1=lock.newCondition();
	  static Condition conditionT2=lock.newCondition();
	  public static void main(String[] args) {
		  
		  
		  new Thread(new Runnable() {
			public void run() {
				try {
					lock.lock();
					for(int i=1;i<=100;i=i+2){
						System.out.println(i);
						conditionT2.signal();
						conditionT1.await();
						
					}
					conditionT1.signal();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}finally {
					lock.unlock();
				}
				
			}
		}).start();
		  
		  new Thread(new Runnable() {
				public void run() {
					try {
						lock.lock();
						for(int i=2;i<=100;i=i+2){
							System.out.println(i);
							conditionT1.signal();
							conditionT2.await();
							
						}
						conditionT2.signal();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}finally {
						lock.unlock();
					}
				}
			}).start();
		
	}
}

**扩展:**编写一个程序,开启 3 个线程,每个线程分别打印A,B,C,要求线程每次打印都按照A–>B–>C的顺序来打印
如:ABCABCABC…… 依次递归

class ShareDate{
	static int num=1;//标志位,t1:1,t2:2,t3:3
	 //获得lock锁
	  static Lock lock=new ReentrantLock();
	  //创建三个condition对象用来await(阻塞)和signal(唤醒)指定的线程
	  private Condition c1=lock.newCondition();
	  private  Condition c2=lock.newCondition();
	  private  Condition c3=lock.newCondition();
	  
	  public void printA(){
		  lock.lock();
		  try {
			//判断
			while(num!=1){
				c1.await();
			}
			//干活
			System.out.println(Thread.currentThread().getName()+"-A");
			//通知
			num=2;//先修改标志位
			c2.signal();//唤醒第二个线程
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
		 
		  System.out.println();
		  
	  }
      public void printB(){
    	  lock.lock();
    	  try {
			while(num!=2){
				c2.await();
			}
			System.out.println(Thread.currentThread().getName()+"-B");
			num=3;
			c3.signal();
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}
		  
	  }
     public void printC(){
	  lock.lock();
	  try {
		while(num!=3){
			c3.await();
		}
		System.out.println(Thread.currentThread().getName()+"-C");
		num=1;
		c1.signal();
	} catch (Exception e) {
		// TODO: handle exception
	}finally{
		lock.unlock();
	}
	  
  }
	  
}
public class Text1 {  
  public static void main(String[] args) {
	  final ShareDate shareDate=new ShareDate();
	  new Thread(new Runnable() {
		public void run() {
			for(int i=1;i<=10;i++){
				shareDate.printA();
			}
		}
	}).start();
	  
	  
	  new Thread(new Runnable() {
			public void run() {
				for(int i=1;i<=10;i++){
					shareDate.printB();
				}
			}
		}).start();
	  
	  new Thread(new Runnable() {
			public void run() {
				for(int i=1;i<=10;i++){
					shareDate.printC();
				}	
			}
		}).start();
	
 }
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值