问题描述:最近遇到一个问题,让你用10个线程计算1-100累加的结果,并且不能使用Synchronize。
思路:用AtomicInteger + 线程池来解决。
tip:不能使用volatile关键字(只能保证可见性,不能保证同步性),用的话需要加锁不符题意
代码如下:
public class Sum1To100With10Thread {
//创建十个线程,计算1加到100的结果,然后合并返回public class Add {//使用原子类
public static void main(String[] args) throws ExecutionException, InterruptedException {
AtomicInteger sum = new AtomicInteger();
CountDownLatch countDownLatch = new CountDownLatch(10);//设置计数器初始值为10
ExecutorService ex = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
ex.execute(() -> {
for (int j = 1; j <= 10; j++) {
sum.addAndGet(i * 10 + j);
}
countDownLatch.countDown();//执行完sum+之后,countDownLatch数量-1
});
}
countDownLatch.await();//等待计数器归零,然后再向下执行
System.out.println(sum);
ex.shutdown();
}
}
遇到问题:Error:(23, 35) java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量

知识点:
Lambda表达式规则
- 只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
- 局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
- 不允许声明一个与局部变量同名的参数或者局部变量。
解决方法:copy ‘i’ to effectively final temp variable
修改后的代码如下:
public class Sum1To100With10Thread {
//创建十个线程,计算1加到100的结果,然后合并返回public class Add {//使用原子类
public static void main(String[] args) throws ExecutionException, InterruptedException {
AtomicInteger sum = new AtomicInteger();//只能用原子类,不能用volatile。如果用volatile得加锁
CountDownLatch countDownLatch = new CountDownLatch(10);
ExecutorService ex = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
int finalI = i; // <--------
ex.execute(() -> {
for (int j = 1; j <= 10; j++) {
sum.addAndGet(finalI * 10 + j); //<--------
}
countDownLatch.countDown();//执行完sum+之后,countDownLatch数量-1
});
}
countDownLatch.await();//等待计数器归零,然后再向下执行
System.out.println(sum);
ex.shutdown();
}
}
运行结果:5050
最后,欢迎对本题有其他解法的大佬,在评论中分享下思路 ~

博客讲述了如何在不使用Synchronized的情况下,利用AtomicInteger和线程池解决10个线程计算1到100的累加问题。在Java中,由于lambda表达式对变量的限制,需要将循环变量`i`复制为final变量,以避免编译错误。最终代码成功实现了并发计算并得到正确结果5050。

被折叠的 条评论
为什么被折叠?



