论坛首页 Java企业应用论坛

Java线程学习笔记(七)java中递增不是原子性

浏览 7608 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (4) :: 隐藏帖 (3)
作者 正文
   发表时间:2010-04-24   最后修改:2010-04-25

以下为测试代码,通过一个自增函数得到最新的值,玩Set你存,看是否有重复。如果递增式原子性的者这个函数不会出错

package com.woxiaoe.study.thread;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 验证Java中递增操作不是递增的
 * @author 小e
 *
 * 2010-4-24 下午09:53:50
 */
public class SerialNumberChecker {
	private static Set<Integer> serialNumberSet = new HashSet<Integer>();
	static int base = 0;
	static int THREAD_SIZE = 10;
	
	static class SerialChecker implements Runnable{
		private SerialNumberChecker snc;
		public SerialChecker(SerialNumberChecker snc) {
			this.snc = snc;
		}
		@Override
		public void run() {
			while(true){
				//int number = snc.nextNumber();
				int number = snc.base ++;
				if(serialNumberSet.contains(number)){
					System.out.println("存在重复值:" + number);
					System.exit(0);
				}else{
					serialNumberSet.add(number);
				}
			}
		}
		
	}
	
	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		SerialNumberChecker snc = new SerialNumberChecker();
		for(int i = 0; i < THREAD_SIZE; i++){
			exec.execute(new SerialChecker(snc));
		}
	}
	
	
	
	
	

}
 

Output:

存在重复值:26202
存在重复值:48602
存在重复值:21441
存在重复值:45719
存在重复值:44544
存在重复值:56256
存在重复值:58230
存在重复值:60097
存在重复值:66177

   发表时间:2010-04-25  
这不能证明递增不是原子性的,只能证明你那个函数不是线程安全的。即使++是原子性的,这个例子也还可能出现你描述的情况。问题是当++完成后,在函数返回前,如果另外一个线程也进入了,然后++了那个变量,然后第一个线程又激活,返回了这个被修改的值,则2个线程返回的值就会相同。
0 请登录后投票
   发表时间:2010-04-25  
wumingshi 写道
这不能证明递增不是原子性的,只能证明你那个函数不是线程安全的。即使++是原子性的,这个例子也还可能出现你描述的情况。问题是当++完成后,在函数返回前,如果另外一个线程也进入了,然后++了那个变量,然后第一个线程又激活,返回了这个被修改的值,则2个线程返回的值就会相同。

 

 嗯那样是不严谨,但是java中递增的确不是原子性,我们可以把代码改一下,不调用方法

package com.woxiaoe.study.thread;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 验证Java中递增操作不是递增的
 * @author 小e
 *
 * 2010-4-24 下午09:53:50
 */
public class SerialNumberChecker {
	private static Set<Integer> serialNumberSet = new HashSet<Integer>();
	public static int base = 0;
	public static int THREAD_SIZE = 10;
	public static int nextNumber(){
		return ++ base;
	}
	static class SerialChecker implements Runnable{
		private SerialNumberChecker snc;
		public SerialChecker(SerialNumberChecker snc) {
			this.snc = snc;
		}
		@Override
		public void run() {
			while(true){
				//int number = snc.nextNumber();
				int number = snc.base ++;
				if(serialNumberSet.contains(number)){
					System.out.println("存在重复值:" + number);
					System.exit(0);
				}else{
					serialNumberSet.add(number);
				}
			}
		}
		
	}
	
	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		SerialNumberChecker snc = new SerialNumberChecker();
		for(int i = 0; i < THREAD_SIZE; i++){
			exec.execute(new SerialChecker(snc));
		}
	}
	
	
	
	
	

}

 Output:

存在重复值:4843
存在重复值:15506
存在重复值:16677
存在重复值:17694
存在重复值:18878
存在重复值:21118
存在重复值:22462
存在重复值:23377
存在重复值:24101

// 还是有重复值的

0 请登录后投票
   发表时间:2010-04-25  
java 的自增自减都不是原子的。。如果要用原子的可以用原子类来做。Java api 上面可找到
0 请登录后投票
   发表时间:2010-04-25   最后修改:2010-04-25
建议lz仔细去阅读一下编译原理。或者使用 atominteger
0 请登录后投票
   发表时间:2010-04-25   最后修改:2010-04-25
NetBus 写道
建议lz仔细去阅读一下编译原理。或者使用 atominteger

呵呵,我的本意是展示这个现象。当然atominteger是一个解决方案。
0 请登录后投票
   发表时间:2010-04-25  
Java自增是原子操作,但是通过函数返回就不是原子操作了。
++ base是原子操作,但是return ++ base;就不是了。
0 请登录后投票
   发表时间:2010-04-25  
haole 写道
Java自增是原子操作,但是通过函数返回就不是原子操作了。
++ base是原子操作,但是return ++ base;就不是了。

别逗了。
0 请登录后投票
   发表时间:2010-04-25  
zhxing 写道
java 的自增自减都不是原子的。。如果要用原子的可以用原子类来做。Java api 上面可找到

嗯 谢谢 嘿嘿我也刚看过了 lz也看看吧
0 请登录后投票
   发表时间:2010-04-25  
whaosoft 写道
zhxing 写道
java 的自增自减都不是原子的。。如果要用原子的可以用原子类来做。Java api 上面可找到

嗯 谢谢 嘿嘿我也刚看过了 lz也看看吧

java编程思想里面有讲
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics