J.U.C 并发包提供了:
AtomicBoolean
AtomicInteger
AtomicLong
- public class Test34 {
- public static void main(String[] args) {
-
- AtomicInteger i = new AtomicInteger(0);
-
- // 获取并自增(i = 0, 结果 i = 1, 返回 0),类似于 i++
- System.out.println(i.getAndIncrement());
- // 自增并获取(i = 1, 结果 i = 2, 返回 2),类似于 ++i
- System.out.println(i.incrementAndGet());
-
- // 自减并获取(i = 2, 结果 i = 1, 返回 1),类似于 --i
- System.out.println(i.decrementAndGet());
- // 获取并自减(i = 1, 结果 i = 0, 返回 1),类似于 i--
- System.out.println(i.getAndDecrement());
-
- // 获取并加值(i = 0, 结果 i = 5, 返回 0)
- System.out.println(i.getAndAdd(5));
- // 加值并获取(i = 5, 结果 i = 0, 返回 0)
- System.out.println(i.addAndGet(-5));
-
- // 获取并更新(i = 0, p 为 i 的当前值, 结果 i = -2, 返回 0)
- // 其中函数中的操作能保证原子,但函数需要无副作用
- System.out.println(i.getAndUpdate(p -> p - 2));
-
- // 更新并获取(i = -2, p 为 i 的当前值, 结果 i = 0, 返回 0)
- // 其中函数中的操作能保证原子,但函数需要无副作用
- System.out.println(i.updateAndGet(p -> p + 2));
-
- // 获取并计算(i = 0, p 为 i 的当前值, x 为参数1, 结果 i = 10, 返回 0)
- // 其中函数中的操作能保证原子,但函数需要无副作用
- // getAndUpdate 如果在 lambda 中引用了外部的局部变量,要保证该局部变量是 final 的
- // getAndAccumulate 可以通过 参数1 来引用外部的局部变量,但因为其不在 lambda 中因此不必是 final
- System.out.println(i.getAndAccumulate(10, (p, x) -> p + x));
-
- // 计算并获取(i = 10, p 为 i 的当前值, x 为参数1, 结果 i = 0, 返回 0)
- // 其中函数中的操作能保证原子,但函数需要无副作用
- System.out.println(i.accumulateAndGet(-10, (p, x) -> p + x));
- }
- }
J.U.C 并发包提供了:
AtomicReference
AtomicMarkableReference
AtomicStampedReference
- @Slf4j(topic = "c.Test35")
- public class Test35 {
- public static void main(String[] args) {
- DecimalAccount.demo(new DecimalAccountCas(new BigDecimal("10000")));
- }
- }
-
- class DecimalAccountCas implements DecimalAccount {
- private AtomicReference
balance; -
- public DecimalAccountCas(BigDecimal balance) {
- // this.balance = balance;
- this.balance = new AtomicReference<>(balance);
- }
-
- @Override
- public BigDecimal getBalance() {
- return balance.get();
- }
-
- @Override
- public void withdraw(BigDecimal amount) {
- while(true) {
- BigDecimal prev = balance.get();
- BigDecimal next = prev.subtract(amount);
- if (balance.compareAndSet(prev, next)) {
- break;
- }
- }
- }
- }
-
- interface DecimalAccount {
- // 获取余额
- BigDecimal getBalance();
-
- // 取款
- void withdraw(BigDecimal amount);
-
- /**
- * 方法内会启动 1000 个线程,每个线程做 -10 元 的操作
- * 如果初始余额为 10000 那么正确的结果应当是 0
- */
- static void demo(DecimalAccount account) {
- List
ts = new ArrayList<>(); - for (int i = 0; i < 1000; i++) {
- ts.add(new Thread(() -> {
- account.withdraw(BigDecimal.TEN);
- }));
- }
- ts.forEach(Thread::start);
- ts.forEach(t -> {
- try {
- t.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- System.out.println(account.getBalance());
- }
- }
- @Slf4j(topic = "c.Test36")
- public class Test36 {
- static AtomicReference
ref = new AtomicReference<>("A"); -
- public static void main(String[] args) throws InterruptedException {
- log.debug("main start...");
- // 获取值 A
- // 这个共享变量被其他线程修改过
- String prev = ref.get();
- other();
- sleep(5);
- // 尝试改为 C
- log.debug("change A->C {}", ref.compareAndSet(prev, "C"));
- }
-
- private static void other() throws InterruptedException {
- new Thread(() -> {
- log.debug("change A->B", ref.compareAndSet(ref.get() ,"B"));
- }, "t1").start();
- sleep( 1);
- new Thread(() -> {
- log.debug("change B->A", ref.compareAndSet(ref.get() ,"A"));
- }, "t2").start();
- }
- }
主线程仅能判断出共享变量的值与最初值 A 是否相同,不能感知到这种从 A 改为 B 又 改回 A 的情况,如果主线程希望:只要有其它线程【动过了】共享变量,那么自己的 cas 就算失败,这时,仅比较值是不够的,需要再加一个版本号
- @Slf4j(topic = "c.Test36")
- public class Test36 {
-
- static AtomicStampedReference
ref = new AtomicStampedReference<>("A", 0); -
- public static void main(String[] args) throws InterruptedException {
- log.debug("main start...");
- // 获取值 A
- String prev = ref.getReference();
- // 获取版本号
- int stamp = ref.getStamp();
- log.debug("版本 {}", stamp);
- // 如果中间有其它线程干扰,发生了 ABA 现象
- other();
- sleep(1);
- // 尝试改为 C
- log.debug("change A->C {}", ref.compareAndSet(prev, "C", stamp, stamp + 1));
- }
-
- private static void other() {
- new Thread(() -> {
- log.debug("change A->B {}", ref.compareAndSet(ref.getReference(), "B", ref.getStamp(), ref.getStamp() + 1));
- log.debug("更新版本为 {}", ref.getStamp());
- }, "t1").start();
- sleep(0.5);
- new Thread(() -> {
- log.debug("change B->A {}", ref.compareAndSet(ref.getReference(), "A", ref.getStamp(), ref.getStamp() + 1));
- log.debug("更新版本为 {}", ref.getStamp());
- }, "t2").start();
- }
- }
但是有时候,并不关心引用变量更改了几次,只是单纯的关心 是否更改过 ,所以就有了AtomicMarkableReference
@Slf4j(topic = "c.Test38") public class Test38 { public static void main(String[] args) throws InterruptedException { GarbageBag bag = new GarbageBag("装满了垃圾"); // 参数2 mark 可以看作一个标记,表示垃圾袋满了 AtomicMarkableReferenceref = new AtomicMarkableReference<>(bag, true); log.debug("start..."); GarbageBag prev = ref.getReference(); log.debug(prev.toString()); new Thread(() -> { log.debug("start..."); bag.setDesc("空垃圾袋"); ref.compareAndSet(bag, bag, true, false); log.debug(bag.toString()); },"保洁阿姨").start(); sleep(1); log.debug("想换一只新垃圾袋?"); boolean success = ref.compareAndSet(prev, new GarbageBag("空垃圾袋"), true, false); log.debug("换了么?" + success); log.debug(ref.getReference().toString()); } } class GarbageBag { String desc; public GarbageBag(String desc) { this.desc = desc; } public void setDesc(String desc) { this.desc = desc; } @Override public String toString() { return super.toString() + " " + desc; } }
J.U.C 并发包提供了:
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
- public class Test39 {
-
- public static void main(String[] args) {
- demo(
- ()->new int[10],
- (array)->array.length,
- (array, index) -> array[index]++,
- array-> System.out.println(Arrays.toString(array))
- );
-
- demo(
- ()-> new AtomicIntegerArray(10),
- (array) -> array.length(),
- (array, index) -> array.getAndIncrement(index),
- array -> System.out.println(array)
- );
- }
-
- /**
- 参数1,提供数组、可以是线程不安全数组或线程安全数组
- 参数2,获取数组长度的方法
- 参数3,自增方法,回传 array, index
- 参数4,打印数组的方法
- */
- // supplier 提供者 无中生有 ()->结果
- // function 函数 一个参数一个结果 (参数)->结果 , BiFunction (参数1,参数2)->结果
- // consumer 消费者 一个参数没结果 (参数)->void, BiConsumer (参数1,参数2)->
- private static
void demo( - Supplier
arraySupplier, - Function
lengthFun, - BiConsumer
putConsumer, - Consumer
printConsumer ) { - List
ts = new ArrayList<>(); - T array = arraySupplier.get();
- int length = lengthFun.apply(array);
- for (int i = 0; i < length; i++) {
- // 每个线程对数组作 10000 次操作
- ts.add(new Thread(() -> {
- for (int j = 0; j < 10000; j++) {
- putConsumer.accept(array, j%length);
- }
- }));
- }
-
- ts.forEach(t -> t.start()); // 启动所有线程
- ts.forEach(t -> {
- try {
- t.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }); // 等所有线程结束
- printConsumer.accept(array);
- }
- }