阿里面试题N个线程循环输出100个数字(非阻塞解法)

背景

最近逛社区看到了一道阿里的面试题,是多线程题目,要求通过N个线程顺序循环打印从0至100。

例如N=3
thread0: 0
thread1: 1
thread2: 3
thread0: 4
thread1: 5复制代码


由于看到的大多都是使用锁来解决问题,最近也是学习java多线程的部分,刚刚看过JDK部分多线程的源码不久有些心得,就想尝试着模仿ReentrantReadWriteLock 操作AQS状态值的思路, 使用 AtomicInteger 来尝试写一下该题目非阻塞的解法。


思路

整体的思路就是通过原子变量存储累积的值以及当前应该执行的线程编号,线程通过自旋来找到能够输出的时机,然后执行最后改变共享的状态值以触发另一线程的执行。


import java.util.concurrent.atomic.AtomicInteger;  

class OutTask extends Thread {
	private final NumOut numOut;
	private final int mark;
	private final int threadCount;

	OutTask(NumOut numOut, int mark, int maxInt) {
		this.mark = mark;
		this.numOut = numOut;
		this.threadCount = maxInt;
	}

	@Override
	public void run() {
		/* 没有输出完全部数字时 保持自旋 */
		/* 通过与操作获取累计数值与最大输出数值比较  */
		while ((this.numOut.state.get() & NumOut.LOW) <= NumOut.MAXNUM) {
			/* 通过与操作获取高16位数值 即 当前应该执行的线程编号 ,并且二次判断数值是否全部输出完毕 */
			if ((this.numOut.state.get() & NumOut.HEIGHT) >> NumOut.NOWMARK_OFFSET == mark
					&& (this.numOut.state.get() & NumOut.LOW) <= NumOut.MAXNUM) {
				
				if (threadCount - 1 == mark) {
					/* 当线程编号达到最后一个时 另做处理 */
					/* 获取当前累计的数值 并输出 */
					int next = (this.numOut.state.get() & NumOut.LOW);
					System.out.println("thread" + mark + ":" + (next));
					/* 计算下一数值 低16位+1 高十六位清0 */
					this.numOut.state.set(next + 1);
				} else {
					/* 获取当前累计的数值 并输出 */
					System.out.println("thread" + mark + ":" + ((this.numOut.state.get() & NumOut.LOW)));
					/* 计算下一数值 高低16位各+1 */
					this.numOut.state.addAndGet(1 + (1 << NumOut.NOWMARK_OFFSET));
				}
			}
		}
	}
}

class NumOut {
	public static final int LOW = 0x0000FFFF;
	public static final int HEIGHT = 0xFFFF0000;
	/* 最大数值 */
	public static final int MAXNUM = 100;
	/* 线程号偏移量 */
	public static final int NOWMARK_OFFSET = 16;
	/* 状态值 */
	final AtomicInteger state = new AtomicInteger(0);
	/* 线程数 */
	final int count;

	public NumOut(int count) {
		// TODO Auto-generated constructor stub
		this.count = count;
	}

	public void outPut() {
		/* 创建任务并启动  */
		for (int i = 0; i < count; i++) {
			Thread a = new OutTask(this, i, count);
			a.start();
		}
	}
}

public class AliTest {
	public static void main(String[] args) {
		NumOut numOut = new NumOut(4);
		numOut.outPut();
	}
} 复制代码


第一次写博客,有很多不足。刚刚工作一年多,越做越发现世界的广大,希望自己能够不断进步。欢迎大家批评指教。


转载于:https://juejin.im/post/5c8b5d88e51d4576dd4f862a

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值