多线程使用-变量共享问题

多线程使用时,有一个常见的问题是变量共享问题。在多线程环境中,多个线程可以同时访问和修改同一个变量,这时就会出现竞态条件和数据不一致的问题。

例如,假设有两个线程同时对一个变量进行递增操作,代码如下:

java 复制代码
public class Counter {
    private int count;

    public void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                counter.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                counter.increment();
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println(counter.getCount());
    }
}

在这个例子中,我们创建了一个计数器类 Counter,其中有一个 count 变量用于记录计数值。我们启动了两个线程 thread1thread2,它们分别对计数器进行了一万次递增操作,并打印最终的计数值。

然而,由于两个线程同时对 count 变量进行修改,会导致竞态条件的产生。即,一个线程读取到了旧的值,然后修改后写入,之后另一个线程读取并修改,覆盖了前一个线程的修改结果,最终导致计数值不准确。

为了解决这个问题,可以使用锁机制来保证同一时间只有一个线程可以访问和修改变量。可以使用 synchronized 关键字或 ReentrantLock 类来实现锁机制。

java 复制代码
public class Counter {
    private int count;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }
}

在这个修改后的代码中,我们引入了一个 lock 对象,用于进行锁定和解锁操作。在 increment() 方法中,我们先获取锁,然后进行递增操作,最后释放锁。这样就能保证同一时间只有一个线程可以修改计数值。

在实际开发中,变量共享问题是一个需要特别注意的问题,如果处理不当可能会引发严重的并发安全问题。因此,在多线程程序中,必须谨慎地处理共享变量,并使用合适的同步机制来保证数据的一致性和正确性。

@Async 异步使用

在Spring Boot中,我们可以使用@Async注解来实现异步方法调用。下面是使用@Async注解的示例代码:

首先,我们需要在Spring Boot的启动类上添加@EnableAsync注解来开启异步支持:

java 复制代码
@SpringBootApplication
@EnableAsync
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

然后,在需要异步执行的方法上添加@Async注解:

java 复制代码
@Service
public class MyService {

    @Async
    public void asyncMethod() {
        // 异步执行的代码
    }
}

最后,在调用异步方法的地方,可以直接调用该方法,方法的执行会在一个新的线程中进行:

java 复制代码
@RestController
public class MyController {

    @Autowired
    private MyService myService;

    @GetMapping("/async")
    public String asyncMethod() {
        myService.asyncMethod();
        return "Async method is invoked.";
    }
}

通过以上配置,当我们访问/async接口时,会触发异步方法的执行,并且可以立即返回结果。

需要注意的是,@Async注解默认使用Spring的SimpleAsyncTaskExecutor来执行异步方法,也可以自定义线程池来处理异步任务,可以通过在启动类中配置TaskExecutor bean来实现:

java 复制代码
@EnableAsync
@Configuration
public class AsyncConfig {

    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(100);
        executor.setQueueCapacity(10);
        executor.initialize();
        return executor;
    }
}

在自定义的线程池中,可以根据实际需求配置线程池的大小、队列容量等参数。

这样,通过@Async注解,我们可以方便地实现异步方法调用,并提高系统的并发处理能力。

以上设置没有问题。实际的开发中,可能会有@Async方法带参数的情况:

java 复制代码
@Service
public class MyService {
    @GetMapping("/async")
    public String asyncMethod(People people) {
        return "Async method is invoked.";
    }
}

asyncMethod方法如果在for循环中调用,一定不能共用实体类.都在在异步线程中会出现变量共享的问题。

java 复制代码
@RestController
public class MyController {

    @Autowired
    private MyService myService;

    @GetMapping("/people")
    public void asyncMethod(List<Man> list) {
    	// People people = new People();
       for(Man man :list){
       		// people 对象如果使用同一个,就会出现问题,必须每次new 一个新对象
       		People people = new People();
       		people.setId(man.getId);
       		myService.asyncMethod(people);
       }
    }
}
相关推荐
dandanforgetlove22 分钟前
python pdfplumber优化表格提取
开发语言·windows·python
ka2x23 分钟前
订单折扣金额分摊算法|代金券分摊|收银系统|积分分摊|分摊|精度问题|按比例分配|钱分摊|钱分配
java·c语言·c++·python·算法·spring·spring cloud
职略2 小时前
负载均衡类型和算法解析
java·运维·分布式·算法·负载均衡
A22742 小时前
LeetCode 196, 73, 105
java·算法·leetcode
容若只如初见3 小时前
项目实战--Spring Boot + Minio文件切片上传下载
java·spring boot·后端
阿里巴巴P8资深技术专家3 小时前
Java常用算法&集合扩容机制分析
java·数据结构·算法
weixin_440401693 小时前
分布式锁——基于Redis分布式锁
java·数据库·spring boot·redis·分布式
码农爱java3 小时前
Spring Boot 中的监视器是什么?有什么作用?
java·spring boot·后端·面试·monitor·监视器
zengson_g4 小时前
当需要对大量数据进行排序操作时,怎样优化内存使用和性能?
java·数据库·算法·排序算法
爱上电路设计4 小时前
有趣的算法
开发语言·c++·算法