多线程访问静态方法中的静态变量

背景:近期,项目中遇到一个场景,多线程访问一个数组,从下标0开始一直到最大长度,然后再从下标0开始,如此循环往复(线程0访问数组下标0,线程1访问数组下标1......)。下标的数值由一个静态变量共享。当时是这么写的,没有考虑多线程的问题:

public class AppUtils {

	private final static int LIMIT = 10;
	private final static int ORIGIN = 0;
	

	// 共享变量
	public static int counter = 0;
	// 错误示范
	public  static int getKeyNumByNext() {
                // 条件重置
		if (counter == LIMIT) {
			counter = ORIGIN;
		}
		System.out.println(Thread.currentThread().getName() +":"+counter);
		counter += 1;
		return counter;
	}

	private CountDownLatch cdl;

	@Test
	public void test() {
		// 模拟并发数
		int concurrentNum = 100;

		cdl = new CountDownLatch(concurrentNum);

		for (int i = 0; i < concurrentNum; i++) {
			new Thread(new UserRequest()).start();
			cdl.countDown();
		}

		try {
			Thread.currentThread().sleep(5000);
			System.out.println("======="+counter);
			//System.out.println("======="+atomCounter.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	class UserRequest implements Runnable {

		@Override
		public void run() {
			try {
				cdl.await();
				// 非安全
				getKeyNumByNext();
				// 安全
				//getAtomKeyNumByNext();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
	}
}

显然,静态变量counter可能在同一时间被多个线程修改,导致条件重置失败(数组下标最大为9,已经有线程到了10+)。


后来,把getKeyNumByNext方法改成了synchronized,保证了变量的线程安全。但是这样肯定会影响性能。于是想起了jdk提供的一种原子操作类型AtomicInteger:

// 原子操作
	public static AtomicInteger atomCounter = new AtomicInteger();

	public static int getAtomKeyNumByNext() {
		atomCounter.incrementAndGet();
		atomCounter.compareAndSet(LIMIT,ORIGIN);
		System.out.println(Thread.currentThread().getName() +":"+atomCounter.get());
		return atomCounter.get();
	}

不仅保证了性能,也保证了计数变量atomCounter的线程安全。这里运用到了一个并发处理的技术: CAS(Compare and swap)。简单的说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替换当前变量的值;如果不等,就重新再取一次:



后台同时指出,还有更简单的方法,把错误示范中的条件重置 的 “==” 改为 “>=”  偷笑


相互探讨,如有缪误,还望指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值