并发编程(1)_CAS
2021/9/14 1:06:36
本文主要是介绍并发编程(1)_CAS,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
问题引出
当我们使用多线程计数操作的时候,我们使用如下代码
package com.mmall.example.count; import javax.xml.bind.SchemaOutputResolver; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * 测试多线程计数类 */ public class Test0913 { //总访问量 static int count = 0; //模拟访问的方法 public static void request() throws InterruptedException { //模拟耗时5毫秒 TimeUnit.MILLISECONDS.sleep(5); count++; } //并发程序 public static void main(String[] args) throws InterruptedException { //计算耗时需要获取当前时间、运行后时间,计算他们之间的差值 long startTime = System.currentTimeMillis(); //设置线程个数 int threadsize = 100; //创建一个栅栏 CountDownLatch countDownLatch = new CountDownLatch(threadsize); for (int i = 0; i < threadsize; i++) { //创建线程 Thread thread = new Thread(new Runnable() { @Override public void run() { //模拟用户行为,每个用户访问十次网站 try { for (int j = 0; j < 10; j++) { request(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { countDownLatch.countDown(); } } }); thread.start(); } //只有await方法的值为0整个程序才会结束 countDownLatch.await(); //拿到程序结束的时间 long endTime = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName() + ",耗时:" + (endTime - startTime) + ", count:" + count); } }
但是从该类的输出结果我们发现了输出的计数值总是不确定的,并且计数值不是我们想要的。这是因为存在线程不同步问题
问题分析
这里问题出自request方法中的count++操作,因为count++语句实际上是需要三步来完成(和jvm有关)
//count操作分解 1. 获取count的值,记作A A = count 2. 将A值+1,得到B B = A+1 3. 将B值赋值给count 如果由a b 两个线程,同时执行count++,那么假如a和b同时执行上面的第一步部操作,最后执行完后a+1、b+1,虽然线程进行了两次加法,但是count相当于只加了一次。
在这里为了避免这种错误,我们希望在执行count++操作的时候,同一时刻只允许一个线程去进行这个操作,因此引出了锁的概念,在java中,我们利用synchronized关键字来实现对资源的加锁。
于是我们将代码改进如下
package com.mmall.example.count; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * 测试多线程计数类 * 对request方法添加了锁 */ public class Test09131 { //总访问量 static int count = 0; //模拟访问的方法 public static synchronized void request() throws InterruptedException { //模拟耗时5毫秒 TimeUnit.MILLISECONDS.sleep(5); count++; } //并发程序 public static void main(String[] args) throws InterruptedException { //计算耗时需要获取当前时间、运行后时间,计算他们之间的差值 long startTime = System.currentTimeMillis(); //设置线程个数 int threadsize = 100; //创建一个栅栏 CountDownLatch countDownLatch = new CountDownLatch(threadsize); for (int i = 0; i < threadsize; i++) { //创建线程 Thread thread = new Thread(new Runnable() { @Override public void run() { //模拟用户行为,每个用户访问十次网站 try { for (int j = 0; j < 10; j++) { request(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { countDownLatch.countDown(); } } }); thread.start(); } //只有await方法的值为0整个程序才会结束 countDownLatch.await(); //拿到程序结束的时间 long endTime = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName() + ",耗时:" + (endTime - startTime) + ", count:" + count); } }
从这个程序的输出结果看
计数准确性问题确实解决了,但是出现了新问题,运行时间变得十分缓慢,这是因为我们的锁加在了整个方法上,导致执行整个request方法在同一时刻只能有一个线程在执行,实际上我们只需要对count++中的第三步操作加锁就可以,这里也引出了我们加锁的原则
在保证线程安全性的情况下,加锁的范围越小越好
这篇关于并发编程(1)_CAS的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享