JUC中原子类的简单用法

一些原子类的简单用法

讲解视频参考B站视频讲解链接

package com;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.*;
import java.util.function.LongBinaryOperator;

/**
 * 学习使用Atomic类的一些常见方法
 */
public class AtomicTest {

	public static final int SIZE = 50;
	public static final int count = 10000;
	public static void main(String[] args) throws InterruptedException {
		test7();

	}


	/**
	 * 案例:热点商品点赞计数器,点赞数使用加加统计,不要求实时精确
	 *
	 * 	 50个线程,每个线程点赞100W次,统计总点赞数
	 *
	 * todo:
	 *  统计比较四种方案的性能
	 *  ----clickBySynchronized cost time: 	1696毫秒	50000000
	 *  ----clickByAtomicLong cost time: 	1091毫秒	50000000
	 *  ----clickByLongAdder cost time: 	155毫秒	50000000
	 *  ----clickByLongAccumulator cost time: 	134毫秒	50000000
	 *  结论:推荐使用LongAdder,该类的性能较高,操作简单
	 *
	 *
	 */
	private static void test7() throws InterruptedException {
		ClickNumber clickNumber = new ClickNumber();

		long startTime;
		long endTime;

		CountDownLatch countDownLatch1 = new CountDownLatch(SIZE);
		CountDownLatch countDownLatch2 = new CountDownLatch(SIZE);
		CountDownLatch countDownLatch3 = new CountDownLatch(SIZE);
		CountDownLatch countDownLatch4 = new CountDownLatch(SIZE);

		startTime = System.currentTimeMillis();
		for (int i = 0; i < SIZE; i++) {
			new Thread(()->{
				try {
					for (int j = 0; j < count * 100; j++) {
						clickNumber.clickBySynchronized();
					}
				} finally {
				    countDownLatch1.countDown();
				}
			}, "t1").start();
		}

		countDownLatch1.await();
		endTime = System.currentTimeMillis();
		System.out.println("----clickBySynchronized cost time: " + "\t"
				+ (endTime - startTime) + "毫秒" + "\t" + clickNumber.number);


		startTime = System.currentTimeMillis();
		for (int i = 0; i < SIZE; i++) {
			new Thread(()->{
				try {
					for (int j = 0; j < count * 100; j++) {
						clickNumber.clickByAtomicLong();
					}
				} finally {
					countDownLatch2.countDown();
				}
			}, "t1").start();
		}

		countDownLatch2.await();
		endTime = System.currentTimeMillis();
		System.out.println("----clickByAtomicLong cost time: " + "\t"
				+ (endTime - startTime) + "毫秒" + "\t" + clickNumber.atomicLong.get());

		startTime = System.currentTimeMillis();
		for (int i = 0; i < SIZE; i++) {
			new Thread(()->{
				try {
					for (int j = 0; j < count * 100; j++) {
						clickNumber.clickByLongAdder();
					}
				} finally {
					countDownLatch3.countDown();
				}
			}, "t1").start();
		}

		countDownLatch3.await();
		endTime = System.currentTimeMillis();
		System.out.println("----clickByLongAdder cost time: " + "\t"
				+ (endTime - startTime) + "毫秒" + "\t" + clickNumber.longAdder.sum());

		startTime = System.currentTimeMillis();
		for (int i = 0; i < SIZE; i++) {
			new Thread(()->{
				try {
					for (int j = 0; j < count * 100; j++) {
						clickNumber.clickByLongAccumulator();
					}
				} finally {
					countDownLatch4.countDown();
				}
			}, "t1").start();
		}

		countDownLatch4.await();
		endTime = System.currentTimeMillis();
		System.out.println("----clickByLongAccumulator cost time: " + "\t"
				+ (endTime - startTime) + "毫秒" + "\t" + clickNumber.longAccumulator.get());
	}


	/**
	 * LongAdder只能从0开始    LongAccumulator可以自定义加减乘除 更加灵活
	 */
	private static void test6() {
		LongAdder adder = new LongAdder();
		adder.increment();
		adder.increment();
		adder.increment();
		System.out.println(adder);

		LongAccumulator accumulator = new LongAccumulator(new LongBinaryOperator() {
			@Override
			public long applyAsLong(long left, long right) {
				return left +right;
			}
		}, 0);
		accumulator.accumulate(1);
		accumulator.accumulate(4);
		System.out.println(accumulator.get());
	}




	/**
	 * 多线程并发调用一个初始化方法,如果未初始化则调用,反之则不
	 */
	private static void test5() {
		MyVar myVar = new MyVar();

		for (int i = 0; i < SIZE; i++) {
			new Thread(()->{
				myVar.init();
			}, String.valueOf(i)).start();
		}

		try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
	}

	/**
	 * 以一种线程安全的方式操作非线程安全的对象中的某个字段
	 * 使用场景:一个账号类BankAccount的实例字段money  如果多个账号给这个对象转钱,
	 * 那么如果add方法使用synchronized修饰,则锁的是整个对象,势必会造成性能降低,
	 * 那么使用AtomicReferenceFieldUpdater可以使money具有原子性!!!
	 * TODO:
	 *      使用AtomicReferenceFieldUpdater实现
	 */
	private static void test4() throws InterruptedException {
		BankAccount bankAccount = new BankAccount();
		CountDownLatch countDownLatch = new CountDownLatch(10);

		for (int i = 0; i < 10; i++) {
			new Thread(()->{
				try {
					for (int i1 = 0; i1 < 1000; i1++) {
						bankAccount.transMoney();
					}
				} finally {
					countDownLatch.countDown();
				}
			}, String.valueOf(i)).start();
		}

		countDownLatch.await();
		System.out.println(bankAccount.money);
	}

	/**
	 * 测试AtomicMarkableReference的用法  AtomicMarkableReference对象只能修改一次!!!!
	 */
	private static void test3() {
		AtomicMarkableReference<Integer> markableReference = new AtomicMarkableReference<>(100, false);

		new Thread(()->{
			boolean marked = markableReference.isMarked();
			try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
			System.out.println(Thread.currentThread().getName() + "\t" + markableReference.compareAndSet(100, 1000, marked, !marked));
			System.out.println(Thread.currentThread().getName() + "\t" + markableReference.compareAndSet(1000, 100, !marked, marked));

		}, "t1").start();


		new Thread(()->{
			boolean marked = markableReference.isMarked();
			try { TimeUnit.MILLISECONDS.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }
			System.out.println(Thread.currentThread().getName() + "\t" + markableReference.compareAndSet(100, 2000, marked, !marked));
			System.out.println(markableReference.getReference());
		}, "t2").start();
		try { TimeUnit.MILLISECONDS.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); }
	}

	/**
	 * 使用CountDownLatch解决test1中的问题
	 */
	private static void test2() throws InterruptedException {
		MyNumber myNumber = new MyNumber();
		CountDownLatch countDownLatch = new CountDownLatch(SIZE);

		for (int i = 1; i <= SIZE; i++) {
			new Thread(()->{
				try {
					for (int j = 0; j < 1000; j++) {
						myNumber.addPlusPlus();
					}
				} finally {
				    countDownLatch.countDown();
				}
			}, "t1").start();
		}
		countDownLatch.await();
		System.out.println(myNumber.atomicInteger.get());
	}

	/**
	 * 虽然没有出现问题,但是具体主线程需要等待多少时间是未知的,在具体的生产环境中并不适用!!!
	 */
	private static void test1() {
		MyNumber myNumber = new MyNumber();

		for (int i = 1; i <= SIZE; i++) {
			new Thread(()->{
				for (int i1 = 0; i1 < 1000; i1++) {
					myNumber.addPlusPlus();
				}
			}, "t1").start();
		}
		try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
		System.out.println(myNumber.atomicInteger.get());
	}
}


class MyVar{
	public volatile Boolean isInit = Boolean.FALSE;

	static final AtomicReferenceFieldUpdater<MyVar, Boolean> referenceFieldUpdater =
			AtomicReferenceFieldUpdater.newUpdater(MyVar.class, Boolean.class, "isInit");

	public void init(){
		try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
		if (referenceFieldUpdater.compareAndSet(this, Boolean.FALSE, Boolean.TRUE)){
			System.out.println(Thread.currentThread().getName() +"\t" + "start init...");
			try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
			System.out.println("over init...");
		}else {
			System.out.println("-------------------------");
		}
	}

}

class MyNumber{
	AtomicInteger atomicInteger = new AtomicInteger();

	public void addPlusPlus(){
		atomicInteger.getAndIncrement();
	}
}

class BankAccount{
	String bankName = "ICBC";
	// AtomicReferenceFieldUpdater要求这个字段必须使用public volatile 修饰
	public volatile int money = 0;

	// 使用静态newUpdater方法创建一个更新器,并且需要设置想要更新的类和属性
	static final AtomicIntegerFieldUpdater<BankAccount> fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(BankAccount.class, "money");


	public void add(){
		money++;
	}

	public void transMoney(){
		fieldUpdater.getAndIncrement(this);
	}

}

/**
 * 统计四种方法的性能
 */
class ClickNumber{
	int number = 0;
	public synchronized void clickBySynchronized(){
		number++;
	}

	public AtomicLong atomicLong = new AtomicLong();
	public void clickByAtomicLong(){
		atomicLong.getAndIncrement();
	}

	public LongAdder longAdder = new LongAdder();
	public void clickByLongAdder(){
		longAdder.increment();
	}

	public LongAccumulator longAccumulator = new LongAccumulator(new LongBinaryOperator() {
		@Override
		public long applyAsLong(long left, long right) {
			return left + right;
		}
	}, 0);
	public void clickByLongAccumulator(){
		longAccumulator.accumulate(1);
	}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值