多线程访问静态方法中的静态变量
2017-09-04 00:39
232 查看
背景:近期,项目中遇到一个场景,多线程访问一个数组,从下标0开始一直到最大长度,然后再从下标0开始,如此循环往复(线程0访问数组下标0,线程1访问数组下标1......)。下标的数值由一个静态变量共享。当时是这么写的,没有考虑多线程的问题:
public class AppUtils {
private final static int LIMIT = 10;
private final static int ORIGIN = 0;
// 共享变量
public static int counter = 0;
// 错误示范
public static int getKeyNumByNext() {
显然,静态变量counter可能在同一时间被多个线程修改,导致条件重置失败(数组下标最大为9,已经有线程到了10+)。
后来,把getKeyNumByNext方法改成了synchronized,保证了变量的线程安全。但是这样肯定会影响性能。于是想起了jdk提供的一种原子操作类型AtomicInteger:
// 原子操作
public static AtomicInteger atomCounter = new AtomicInteger();
public static int getAtomKeyNumByNext() {
atomCounter.incrementAndGet();
atomCounter.compareAndSet(LIMIT,ORIGIN);
System.out.println(Thread.currentThread().getName() +":"+atomCounter.get());
return atomCounter.get();
}
不仅保证了性能,也保证了计数变量atomCounter的线程安全。这里运用到了一个并发处理的技术:CAS(Compare and swap)。简单的说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替换当前变量的值;如果不等,就重新再取一次:
后台同时指出,还有更简单的方法,把错误示范中的条件重置 的 “==” 改为 “>=”
相互探讨,如有缪误,还望指正。
public class AppUtils {
private final static int LIMIT = 10;
private final static int ORIGIN = 0;
// 共享变量
public static int counter = 0;
// 错误示范
public static int getKeyNumByNext() {
// 条件重置 if (counter == LIMIT) { counter = ORIGIN; } System.out.println(Thread.currentThread().getName() +":"+counter); counter += 1; return counter; } private CountDownLatch cdl; @Test public void test() { // 模拟并发数 int concurrentNum = 100; cdl = new CountDownLatch(concurrentNum); for (int i = 0; i < concurrentNum; i++) { new Thread(new UserRequest()).start(); cdl.countDown(); } try { Thread.currentThread().sleep(5000); System.out.println("======="+counter); //System.out.println("======="+atomCounter.get()); } catch (InterruptedException e) { e.printStackTrace(); } } class UserRequest implements Runnable { @Override public void run() { try { cdl.await(); // 非安全 getKeyNumByNext(); // 安全 //getAtomKeyNumByNext(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
显然,静态变量counter可能在同一时间被多个线程修改,导致条件重置失败(数组下标最大为9,已经有线程到了10+)。
后来,把getKeyNumByNext方法改成了synchronized,保证了变量的线程安全。但是这样肯定会影响性能。于是想起了jdk提供的一种原子操作类型AtomicInteger:
// 原子操作
public static AtomicInteger atomCounter = new AtomicInteger();
public static int getAtomKeyNumByNext() {
atomCounter.incrementAndGet();
atomCounter.compareAndSet(LIMIT,ORIGIN);
System.out.println(Thread.currentThread().getName() +":"+atomCounter.get());
return atomCounter.get();
}
不仅保证了性能,也保证了计数变量atomCounter的线程安全。这里运用到了一个并发处理的技术:CAS(Compare and swap)。简单的说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替换当前变量的值;如果不等,就重新再取一次:
后台同时指出,还有更简单的方法,把错误示范中的条件重置 的 “==” 改为 “>=”
相互探讨,如有缪误,还望指正。
相关文章推荐
- 静态变量和静态方法的访问权限
- java 程序加载过程---3--类中申明同时申明类的静态对象 创建类的实例 访问类的静态变量 调用类的静态方法 使用反射方法 初始化类的子类对象 直接使用java.exe 调用某个类
- 静态变量和静态方法的访问
- JavaSE7基础 类中 静态方法只能访问静态变量
- 内部类访问外部类的变量必须是final吗,java静态方法中不能引用非静态变量,静态方法中不能创建内部类的实例
- struts2中OGNL中访问静态变量和静态方法
- 类的静态变量和 静态方法就可以直接用类名进行访问
- Struts2 中 OGNL 如何更简单的访问静态变量和静态方法
- 静态方法在多线程下的调用
- java基础---静态变量、静态块、非静态块、构造函数及静态方法总结及一点儿想法
- 多线程:synchronized 关键字用法(修饰类,方法,静态方法,代码块)
- JAVA的静态变量、静态方法、静态类
- java:静态方法,静态变量,实例方法,实例变量的关系 ----李雪
- Java多线程 6 静态同步方法的锁
- 小东吖 之 java 构造方法 static关键字 静态变量 静态方法
- C++静态成员函数访问非静态成员的几种方法
- Java---类加载机制,构造方法,静态变量,(静态)代码块,父类,变量加载顺序
- Java静态方法,静态变量,初始化顺序
- Java中静态变量与静态方法的继承
- 多线程有几种实现方法?同步有几种实现方法?静态同步方法和非静态有何不同?—— Java经典面试题系列