多线程下实现自增的几种方式
使用synchronized加锁
发布日期:2021-04-30 21:03:10
浏览次数:103
分类:精选文章
本文共 5363 字,大约阅读时间需要 17 分钟。
多线程环境下i++操作的实现问题
在多线程环境下,直接使用i++操作可能会引发严重的竞态条件,导致无法达到预期的效果。以下将从多个角度分析这一问题,并探讨解决方案。
直接自增操作的错误
首先,我们来看直接使用i++的多线程实现方式。以下代码片段展示了一个简单的多线程程序:
public class byte1 extends Thread { static int a = 0; @Override public void run() { for (int i = 1; i <= 10000; i++) { a++; } } public static void main(String[] args) { long nowTimeMillis = System.currentTimeMillis(); byte1 tByte1 = new byte1(); List threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }} 运行结果显示,多线程直接自增操作无法正确增加到100000,结果差距很大。这是因为i++操作并非原子操作,容易在多线程环境下出现竞态条件。
volatile的可见性不足
接下来,我们尝试通过volatile来解决这个问题。以下是修改后的代码:
public class byte1 extends Thread { volatile static int a = 0; @Override public void run() { for (int i = 1; i <= 10000; i++) { a++; } } public static void main(String[] args) { long nowTimeMillis = System.currentTimeMillis(); byte1 tByte1 = new byte1(); List threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }} 尽管使用了volatile关键字,结果仍然无法达到预期。这是因为volatile只能保证可见性和指令不重排,但无法保证原子性。例如,当一个线程读取a的值时,另一个线程可能已经修改了a,这会导致读取到的值不正确。
正确的实现方案
为了确保i++操作的原子性,我们可以采用以下方法:
通过对代码块加锁,可以确保在多线程环境下操作的原子性。以下是修改后的代码:
public class byte1 extends Thread { static int a = 0; @Override public void run() { synchronized (this) { for (int i = 1; i <= 10000; i++) { a++; } } } public static void main(String[] args) { long nowTimeMillis = System.currentTimeMillis(); byte1 tByte1 = new byte1(); List threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }} - 使用AtomicInteger
- 使用LongAdder
AtomicInteger提供了一个线程安全的原子性增量操作。以下是修改后的代码:
public class byte1 extends Thread { static AtomicInteger a = new AtomicInteger(0); @Override public void run() { for (int i = 1; i <= 10000; i++) { a.incrementAndGet(); } } public static void main(String[] args) { long nowTimeMillis = System.currentTimeMillis(); byte1 tByte1 = new byte1(); List threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a.get()); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }} LongAdder提供了一个线程安全的原子性加法操作。以下是修改后的代码:
public class byte1 extends Thread { static LongAdder a = new LongAdder(); @Override public void run() { for (int i = 1; i <= 10000; i++) { a.increment(); } } public static void main(String[] args) { long nowTimeMillis = System.currentTimeMillis(); byte1 tByte1 = new byte1(); List threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }} 通过以上方法,我们可以确保在多线程环境下正确实现i++操作,避免竞态条件带来的问题。选择哪种方法取决于具体的需求和性能考虑。
发表评论
最新留言
路过按个爪印,很不错,赞一个!
[***.219.124.196]2026年06月07日 19时12分14秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
PHP版本升级5.4手记
2023-03-01
php版本升级总结
2023-03-01
php版本微信公众号开发
2023-03-01
php版的微信公众号开发演示
2023-03-01
php生成html文件的多种方法介绍
2023-03-01
php生成二维码到图片上
2023-03-01
php生成二维码并下载图片(适应于框架)
2023-03-01
PHP生成及获取JSON文件的方法
2023-03-01
PHP生成唯一不重复的编号
2023-03-01
PHP生成器-动态生成内容的数组
2023-03-01
PHP的ip2long和long2ip升级函数
2023-03-01
php的web路径获取
2023-03-01
php的一些小笔记--字符串
2023-03-01
php的几种运行模式CLI、CGI、FastCGI、mod_php
2023-03-01
php的四大特性八大优势
2023-03-01
RabbitMQ
2023-03-01
PHP的威胁函数与PHP代码审计实战
2023-03-01
PHP的引用举例
2023-03-01