Java并发问题及如何避免 红太狼 2023-10-05 02:23 3阅读 0赞 当代码由多个线程执行时,会出现并发问题。然后,与单线程执行相比,您的代码的行为可能会有所不同,具体取决于何时和哪个线程访问变量。 这是一个例子: import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class ConcurrentTest { static int counter = 0; public static void main(String[] args) throws InterruptedException { ExecutorService service = Executors.newFixedThreadPool(10); for (int i = 0; i < 1000; i++) service.submit(() -> ++counter); service.shutdown(); service.awaitTermination(10, TimeUnit.SECONDS); if (service.isShutdown()) System.out.printf("Total count: %d", counter); } } 在上面的代码中: * 从0开始有一个静态变量计数器。 * 创建具有10个线程的固定线程池执行程序(服务)。在多个线程中执行代码是必需的。 * 创建具有1000次重复的迭代以增加计数器变量。 * 该服务将关闭,等待时间为10秒。 * 一旦我们确认服务已关闭,便会打印总数。 在单个线程中执行的同一代码将使计数器变为1000。您可以通过使用Executors.newFixedThreadPool(1)实例化服务来进行验证。 但是,在有多个线程的情况下(在我们的示例中为10个),当您执行上述代码时,计数器值会有所不同–根据随机因素,它可能是600、900或其他任何值。 这种随机性的原因是增量操作++不是线程安全的。这意味着一个线程获取counter的值,开始递增它的值,同时一个或多个线程也获取相同的counter值并递增。 当第一个线程完成计数器的递增时,它将返回旧值+1。其余线程也一样。因此,如果当两个或多个线程同时尝试增加计数器值时计数器值为111,则当所有并发线程完成时该计数器值为112。 为了克服这个问题,有一些原子类。原子意味着将执行一个操作而不会受到其他线程的干扰。在我们的示例中,我们必须像这样使用AtomicInteger代替原始int: import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerTest { static AtomicInteger counter = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException { ExecutorService service = Executors.newFixedThreadPool(10); for (int i = 0; i < 1000; i++) service.submit(() -> counter.incrementAndGet()); service.shutdown(); service.awaitTermination(10, TimeUnit.SECONDS); if (service.isShutdown()) System.out.printf("Total count: %d", counter.get()); } } 在上面的代码中,对于原始类型整数,AtomicInteger方法crementAndAndGet()等于++,确保每个线程自动获取,递增和设置值,即不干扰其他线程。 与AtomicInteger相似,还有一个用于布尔值的AtomicBoolean类,一个用于long的AtomicLong等。对于集合,有一个ConcurrentHashMap用于哈希图,CopyOnWriteArrayList用于列表等等。这个想法很相似–在使用共享对象时确保线程安全。每个类分别具有不同的方法来帮助您执行可用的原子操作。 原子类的使用似乎是一个非常简单的例程,并且人们可能想知道为什么首先要有非原子类。原因之一是在时间上运行原子操作会产生成本。每个线程将必须与其余线程同步,并在必要时等待它们。设计代码时请牢记这一点,并确保与单线程执行相比,多线程不会使程序变慢,因为线程正在等待共享资源。
相关 如何避免Java多线程并发问题 Java多线程并发问题是由于多个线程同时访问共享资源,导致数据的不一致。以下是一些避免并发问题的方法: 1. **同步机制**: - 使用`synchronized`关 「爱情、让人受尽委屈。」/ 2024年09月16日 14:45/ 0 赞/ 11 阅读
相关 Java并发编程:如何避免死锁问题 死锁是多线程编程中的一种严重问题,当两个或更多的线程在执行过程中因争夺资源而造成的一种互相等待的现象称为死锁。 为了避免死锁,可以遵循以下策略: 1. **预防死锁**: - 日理万妓/ 2024年09月16日 10:18/ 0 赞/ 14 阅读
相关 困惑:Java集合框架如何避免并发问题? 在Java集合框架中,确实存在一些设计来帮助开发者避免并发问题。以下是一些主要的策略: 1. **同步容器**: Java提供了一些线程安全的集合类,比如`Concur 心已赠人/ 2024年09月14日 19:51/ 0 赞/ 7 阅读
相关 如何在Java项目中避免并发问题 在Java项目中避免并发问题,可以通过以下几个方面进行: 1. **使用线程安全的类和集合**:如`java.util.concurrent.locks.ReentrantL r囧r小猫/ 2024年09月14日 17:57/ 0 赞/ 22 阅读
相关 在Java编程中,如何避免并发问题 在Java编程中,避免并发问题主要需要以下几个方面的理解和实践: 1. **使用synchronized关键字**:对于多线程共享资源的场景,可以使用`synchronize 客官°小女子只卖身不卖艺/ 2024年09月12日 14:30/ 0 赞/ 16 阅读
相关 在Java中如何避免并发一致性问题 在Java中,避免并发一致性问题主要通过以下几种方式: 1. **synchronized**:这是最直接的线程同步方法。在一个方法或者代码块前加上`synchronized ゞ 浴缸里的玫瑰/ 2024年09月12日 13:24/ 0 赞/ 15 阅读
相关 在Java开发中如何避免并发问题? 在Java开发中,避免并发问题主要从以下几个方面进行: 1. **使用线程安全的类和集合**: Java提供了许多线程安全的类,如`synchronized`, `ja 朴灿烈づ我的快乐病毒、/ 2024年09月12日 04:00/ 0 赞/ 16 阅读
相关 如何避免Java中常见的并发问题? 在Java中,常见的并发问题包括死锁、饥饿、活锁、数据不一致等。以下是一些避免这些问题的策略: 1. **使用线程池**:线程池可以复用已创建的线程,减少新线程的创建,从而防 我就是我/ 2024年09月11日 06:57/ 0 赞/ 13 阅读
相关 Java并发问题及如何避免 当代码由多个线程执行时,会出现并发问题。然后,与单线程执行相比,您的代码的行为可能会有所不同,具体取决于何时和哪个线程访问变量。 这是一个例子: import ja 红太狼/ 2023年10月05日 02:23/ 0 赞/ 4 阅读
还没有评论,来说两句吧...