java并发---AtomicBoolean的方法compareAndSet(仅执行一次)

本文介绍Java中的AtomicBoolean类,展示了如何使用它来确保线程安全地进行一次性的初始化操作。通过对比volatile变量的方法,强调了AtomicBoolean在高并发场景下的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AtomicBoolean在java.util.concurrent.atomic包下,源代码如下,同样用CAS方法。

AtomicBoolean 可用在应用程序中(如以原子方式更新的标志),但不能用于替换 Boolean。即能够保证在高并发的情况下只有一个线程能够访问这个属性值。

    /**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(boolean expect, boolean update) {
        int e = expect ? 1 : 0;
        int u = update ? 1 : 0;
        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
    }

一般情况下,我们使用 AtomicBoolean 高效并发处理 “只初始化一次” 的功能要求:

    private static AtomicBoolean initialized = new AtomicBoolean(false);
    public void init()
    {
       if( initialized.compareAndSet(false, true) )//如果为false,更新为true
       {
           // 这里放置初始化代码....
       }
    }

如果没有AtomicBoolean,我们可以使用volatile做如下操作:

    public static volatile initialized = false;
    public void init()
    {
        if( initialized == false ){
            initialized = true;
            // 这里初始化代码....
        }
    }

具体实现代码如下:

package concurrency.example.atomic;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;

/*
 *Created by William on 2018/4/28 0028
 */
@Slf4j
public class AtomicExample7Boolean {
    private static AtomicBoolean isHappened = new AtomicBoolean(false);
    public static int clientTotal = 5000;
    public static int threadTotal = 200;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    test();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("isHappened:{}", isHappened.get());
    }

    public static void test() {
        if (isHappened.compareAndSet(false, true)) {
            log.info("execute");
        }
    }
}


<think>好的,用户问的是如何在Java中让一个方法执行一次。我得先理解他的需求。通常这种需求出现在初始化、配置加载或者单例模式中,确保某些关键代码不会重复运行。 首先,我应该考虑不同的实现方式。常见的办法包括使用静态标志位、单例模式、原子类,或者利用Java内置的类如CountDownLatch。可能还要提到Java 8的CompletableFuture,不过得确认用户是否熟悉这些较新的特性。 用户可能是个刚学Java的开发者,所以解释要清晰,步骤明确。要确保每种方法的示例代码正确,语法没问题。比如静态标志位的话,用boolean,但得注意线程安全问题。如果是多线程环境,可能需要用synchronized或者AtomicBoolean。 然后,单例模式也是常见的方式,尤其是懒汉式或者枚举单例。这里需要简单说明单例的原理,并给出示例。可能用户对设计模式不太熟,所以例子要简单直接。 另外,CountDownLatch和CompletableFuture可能用户不太熟悉,但如果有高并发需求,这些方法更可靠。需要说明它们的适用场景,比如CountDownLatch适合等待初始化完成,而CompletableFuture可以处理异步执行的情况。 还要考虑用户可能遇到的陷阱,比如在静态标志位中没有同步导致多次执行,或者单例模式的双重检查锁定问题。这时候需要指出线程安全的重要性,并提供相应的解决方案,比如用volatile或者AtomicBoolean。 最后,总结部分要对比各种方法的优缺点,帮助用户根据具体情况选择。比如简单场景用静态变量,多线程用Atomic或单例,异步用CompletableFuture等。 检查一下示例代码是否正确,特别是LaTeX部分是否符合要求,不过用户的问题是关于Java代码,可能不需要数学公式,但系统指令提到行内数学表达式要用$...$,但这里可能用不上,所以可能没有数学内容。不过要确保代码格式正确,用反引号包裹,语法正确。 可能需要验证每个示例代码是否真的能确保只执行一次,比如静态标志位在多次调用时是否会失效,或者synchronized是否有效防止多线程问题。 总之,整理出几种主要方法,按实现难度和适用场景排序,给出代码示例,并说明优缺点,帮助用户理解选择。</think>在Java中实现方法执行一次的需求,可通过以下5种方式实现,按实现复杂度由低到高排列: 一、静态标志位(基础版) ```java public class SingletonExample { private static boolean hasExecuted = false; public static void executeOnce() { if (!hasExecuted) { System.out.println("方法执行"); hasExecuted = true; } } } ``` 特点:简单易用但线程不安全 二、synchronized同步块(线程安全版) ```java public class SyncExample { private static boolean hasExecuted = false; public static synchronized void executeOnce() { if (!hasExecuted) { System.out.println("线程安全执行"); hasExecuted = true; } } } ``` 特点:保证线程安全,但存在同步开销 三、Atomic原子类(高效线程安全) ```java import java.util.concurrent.atomic.AtomicBoolean; public class AtomicExample { private static AtomicBoolean executed = new AtomicBoolean(false); public static void executeOnce() { if (executed.compareAndSet(false, true)) { System.out.println("原子操作执行"); } } } ``` 特点:无锁竞争,性能更优 四、枚举单例模式(Effective Java推荐) ```java public enum Singleton { INSTANCE; private boolean executed = false; public void executeOnce() { if (!executed) { System.out.println("单例模式执行"); executed = true; } } } ``` 调用方式:`Singleton.INSTANCE.executeOnce();` 特点:线程安全且防反射攻击 五、CompletableFuture(异步执行场景) ```java public class AsyncExample { private static CompletableFuture<Void> future; public static void executeOnceAsync() { if (future == null) { future = CompletableFuture.runAsync(() -> { System.out.println("异步执行一次"); }); } } } ``` 特点:适用于异步初始化场景 选择建议: 1. 单线程环境:选方案一 2. 高并发场景:优先选方案三或四 3. 需要延迟初始化:选方案五 4. 需要防御反射/反序列化:选方案四 注意事项: - 方案二存在"双重检查锁定"问题,需配合volatile使用 - 方案三的AtomicBoolean.compareAndSet()是原子操作 - 方案四通过JVM保证枚举实例的唯一性 - 方案五需注意异常处理和任务取消机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值