【Java】多线程按序打印-新手易读版(附关闭线程方法-牛客网超时解决)

前言

如题,今天搜多线程按序打印的时候,发现大佬们基本都用了Lock或者特殊类来完成“按序”,即使使用了synchronize,也还是用了一些已有类。所以我想如何不用特殊类,只用java本身的基本语法和多线程本身的特性完成同样的效果,所以有了以下代码。

代码1-定义多个实现Runnable的类


/** 

* @author 作者 wuyuzhuo: 

* @version 创建时间:2021年3月20日 下午5:06:56 

* 类说明 

*/
public class Test1_1 {
	static Integer flag=-1;
	static int count = 1;
	static final Object OBJECT = new Object();
	public static class MyThread1 implements Runnable{

		@Override
		public void run() {
			// TODO Auto-generated method stub
			
			while(count<=75) {
				synchronized (OBJECT) {
					if(flag==0) {
						for (int i = 0; i < 5; i++) {
							System.out.println("线程1:"+count);
							count++;
						}System.out.println();
						flag++;
						flag%=3;
//						OBJECT.notifyAll();
					}
					try {
						OBJECT.notifyAll();
						OBJECT.wait();
					}catch (Exception e) {
						// TODO: handle exception
					}
				}

			}

		}
		
	}
	public static class MyThread2 implements Runnable{

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(count<=75) {
				synchronized (OBJECT) {
					if(flag==1) {
						for (int i = 0; i < 5; i++) {
							System.out.println("线程2:"+count);
							count++;
						}System.out.println();
						flag++;
						flag%=3;
//						OBJECT.notifyAll();
					}
					try {
						OBJECT.notifyAll();
						OBJECT.wait();
					}catch (Exception e) {
						// TODO: handle exception
					}
				}

			}

		}
		
	}
	public static class MyThread3 implements Runnable{

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(count<=75) {
				synchronized (OBJECT) {
					if(flag==2) {
						for (int i = 0; i < 5; i++) {
							System.out.println("线程3:"+count);
							count++;
						}System.out.println();
						flag++;
						flag%=3;
//						OBJECT.notifyAll();
					}
					try {
						OBJECT.notifyAll();
						OBJECT.wait();
					}catch (Exception e) {
						// TODO: handle exception
					}
				}

			}
		}
		
	}
	
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub

		flag=0;
		
		MyThread1 thread1 = new MyThread1();
		MyThread2 thread2 = new MyThread2();
		MyThread3 thread3 = new MyThread3();
		
		Thread t1=new Thread(thread1);//.start();
		Thread t2=new Thread(thread2);//.start();
		Thread t3=new Thread(thread3);//.start();
		t1.start();
		t2.start();
		t3.start();
		
		Thread.sleep(10);
		
		t1.interrupt();
		t2.interrupt();
		t3.interrupt();

	}
		

}

代码2-定义一个实现Runnable的类

/** 

* @author 作者 wuyuzhuo: 

* @version 创建时间:2021年3月21日 上午12:30:02 

* 类说明 

*/
public class Test1_2 {
	public static class MyRunnable implements Runnable{
		static int flag;
		static int count=1;
		static final Object object=new Object();
		int signal;
		public MyRunnable(int s) {
			// TODO Auto-generated constructor stub
			signal=s;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(count<=75) {
				synchronized (object) {
					if((signal-1)==flag) {
						for(int i=0;i<5;i++) {
							System.out.println("线程"+signal+":"+count);
							count++;
						}System.out.println();
						flag++;
						flag%=3;
					}
					
					try {
						object.notifyAll();
						object.wait();
					}catch (InterruptedException e) {
						// TODO: handle exception
						System.out.print("Thread "+signal+" has been interrupted!");
//						e.printStackTrace();
					}
				}
			}
		}
		
	}

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		Thread t1=new Thread(new MyRunnable(1));
		Thread t2=new Thread(new MyRunnable(2));
		Thread t3=new Thread(new MyRunnable(3));
		
		t1.start();
		t2.start();
		t3.start();
		
		Thread.sleep(5);
		
		t1.interrupt();
		t2.interrupt();
		t3.interrupt();
	}

}

解释说明

  1. 上程序实现了三线程按续打印1~75,每个线程每次打印5个。
  2. 代码1三个线程是专门写了三个类分别实现的,这是为了便于理解,实际上可以优化成只写一个线程类(见代码2)
  3. 运行结束后,希望线程关闭。有的博客说线程会在while(count<=75)跳出后自动关闭,之前我也是这么以为的(所以被坑惨了),但事实上从我在eclipse和在牛客网分别跑的结果来看,其实并没有。牛客网会报超时,而eclipse控制台始终不会terminate(终止)。所以这也是为什么主程序要加以下代码的原因:
    Thread.sleep(10); t1.interrupt(); t2.interrupt(); t3.interrupt();——通过interrupt中断来优雅的停止线程,同时为了保证我们确实是在所有线程完成本职工作后才中断(这能保证线程确实被终止,而非之后仍会被唤醒导致停止失效)【这里总感觉有更好地方法,即无论运行了多久,在检测到终止条件后当前线程终止,但暂时还没查到资料】
  4. 本代码中使用一个静态的Object对象来管理synchronize,这相当于一个信号量;使用flag来保证线程先后顺序,进入后若不符合要求则自动让出资源。之所以不用flag来管理,是因为synchronize不能用int来管理。这些和我们在计算机组成原理一面学到的同步锁和信号量部分相对应。

运行结果

后面省略不截图了

参考链接

(所有写之前看过的文章,有的不完全对,方便以后复盘)
如何正确地结束一个线程
IllegalMonitorStateException异常原因及解决办法
Java多线程顺序打印abc的多种写法
三线程按顺序交替打印ABC的四种方法
synchronized 锁不住 Integer ?
java线程的取消与关闭

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值