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);// 0for (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);// 0List<Thread> list = new ArrayList<>();// 启动10000个线程同时访问计数器for (int i = 0; i < 10000; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic 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);// 0List<Thread> list = new ArrayList<>();// 启动10000个线程同时访问计数器for (int i = 0; i < 10000; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic 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);// 0List<Thread> list = new ArrayList<>();// 启动10000个线程同时访问计数器for (int i = 0; i < 10000; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic 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
参考
- 使用Atomic-廖雪峰的官方网站
- CAS锁机制(无锁、自旋锁、乐观锁、轻量级锁)
- java中的Atomic类