Java:从单线程计数器到多线程数据同步synchronized和原子类Atomic

简介: Java:从单线程计数器到多线程数据同步synchronized和原子类Atomic

目录

使用单线程

使用多线程

使用多线程 + synchronized

使用多线程 + 原子类AtomicLong

使用单线程

单线程修改计数器的值,没有发生问题,每次运行结果都是10000,不过程序耗时较长


package com.example;


/**

* 计数器

*/

class Counter {

   private static long count;


   public static long getCount() {

       return count;

   }


   public static void incrementCount() {

       count++;

   }

}



public class Demo {

   public static void main(String[] args) throws InterruptedException {

       long count = Counter.getCount();

       System.out.println(count);

       // 0


       for (int i = 0; i < 10000; i++) {

           try {

               Thread.sleep(1);

           } catch (InterruptedException e) {

               e.printStackTrace();

           }

           Counter.incrementCount();

       }

     

       count = Counter.getCount();

       System.out.println(count);

       // 10000

   }

}



使用多线程

单线程修改计数器的值,运行速度提高了,不过运行结果每次都不一致,而且结果不是10000


package com.example;


import java.util.ArrayList;

import java.util.List;


/**

* 计数器

*/

class Counter {

   private static long count;


   public static long getCount() {

       return count;

   }


   public static void incrementCount() {

       count++;

   }

}



public class Demo {

   public static void main(String[] args) throws InterruptedException {

       long count = Counter.getCount();

       System.out.println(count);

       // 0


       List<Thread> list = new ArrayList<>();


       // 启动10000个线程同时访问计数器

       for (int i = 0; i < 10000; i++) {

           Thread thread = new Thread(new Runnable() {

               @Override

               public void run() {

                   try {

                       Thread.sleep(1);

                   } catch (InterruptedException e) {

                       e.printStackTrace();

                   }

                   Counter.incrementCount();

               }

           });

           list.add(thread);

       }


       for (Thread thread : list) {

           thread.start();

       }


       for (Thread thread : list) {

           thread.join();

       }


       count = Counter.getCount();

       System.out.println(count);

   }


执行结果


第一次:9910

第二次:9912

第三次:9910


使用多线程 + synchronized

多线程加锁后,最后结果都是10000


package com.example;


import java.util.ArrayList;

import java.util.List;


/**

* 计数器

*/

class Counter {

   private static long count;


   public static long getCount() {

       return count;

   }


   public static synchronized void incrementCount() {

       count++;

   }

}



public class Demo {

   public static void main(String[] args) throws InterruptedException {

       long count = Counter.getCount();

       System.out.println(count);

       // 0


       List<Thread> list = new ArrayList<>();


       // 启动10000个线程同时访问计数器

       for (int i = 0; i < 10000; i++) {

           Thread thread = new Thread(new Runnable() {

               @Override

               public void run() {

                   try {

                       Thread.sleep(1);

                   } catch (InterruptedException e) {

                       e.printStackTrace();

                   }

                   Counter.incrementCount();

               }

           });

           list.add(thread);

       }


       for (Thread thread : list) {

           thread.start();

       }


       for (Thread thread : list) {

           thread.join();

       }


       count = Counter.getCount();

       System.out.println(count);

   }

}


执行结果


第一次:10000

第二次:10000

第三次:10000


使用多线程 + 原子类AtomicLong

多线程中使用原子类AtomicLong实现计数器,最后结果都是10000


原理是CAS(Compare and Set):


先比较原始值和预期值,如果相等,则修改为新值;

不相等则修改失败

伪代码如下


bool compareAndSet(oldValue, expectValue, updateValue){

   if(oldValue == expectValue){

       oldValue = updateValue

       // update success

   } else{

       // update fail

   }

}


package com.example;


import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.atomic.AtomicLong;


/**

* 计数器

*/

class Counter {

   private static AtomicLong count = new AtomicLong(0);


   public static long getCount() {

       return count.get();

   }


   public static void incrementCount() {

       count.incrementAndGet();

   }

}



public class Demo {

   public static void main(String[] args) throws InterruptedException {

       long count = Counter.getCount();

       System.out.println(count);

       // 0


       List<Thread> list = new ArrayList<>();


       // 启动10000个线程同时访问计数器

       for (int i = 0; i < 10000; i++) {

           Thread thread = new Thread(new Runnable() {

               @Override

               public void run() {

                   try {

                       Thread.sleep(1);

                   } catch (InterruptedException e) {

                       e.printStackTrace();

                   }

                   Counter.incrementCount();

               }

           });

           list.add(thread);

       }


       for (Thread thread : list) {

           thread.start();

       }


       for (Thread thread : list) {

           thread.join();

       }


       count = Counter.getCount();

       System.out.println(count);

   }

}


执行结果


第一次:10000

第二次:10000

第三次:10000

————————————————

版权声明:本文为CSDN博主「彭世瑜」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/mouday/article/details/130923836

相关文章
|
20天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
20天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
14天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
14天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
38 3
|
20天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
73 6
|
20天前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
54 1
|
21天前
|
设计模式 安全 Java
Java 多线程并发编程
Java多线程并发编程是指在Java程序中使用多个线程同时执行,以提高程序的运行效率和响应速度。通过合理管理和调度线程,可以充分利用多核处理器资源,实现高效的任务处理。本内容将介绍Java多线程的基础概念、实现方式及常见问题解决方法。
41 0
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
58 1
C++ 多线程之初识多线程
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
27 3
|
2月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
23 2