zoukankan      html  css  js  c++  java
  • 多线程并发之原子性(六)

    最近在网上找到好多的多线程关于原子性的例子,说的都不是非常的明确,对于刚学习多线程的新手而言很容误导学员,在这里,我通过多个例子对多线程的原子性加以说明。

    例子一:传统技术自增

    package face.thread.volatilep;
    
    public class Counter2 {
        private  int count = 0; 
        public synchronized void inc() {
            count = count + 1;
        }
     
        public static void main(String[] args) {
     
            //同时启动1000个线程,去进行i++计算,看看实际结果
        	final Counter2 c = new Counter2();
        	
            for (int i = 0; i < 1000; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                    	c.inc();
                    }
                }).start();
            }
            
            try {
    			Thread.sleep(1000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
            //这里每次运行的值都有可能不同,可能为1000
            System.out.println("运行结果:Counter.count=" + c.count);
        }
    }


    以上代码打印的结果偶尔会等于1000,基本上都会有一些误差,原因是线程执行的顺序无法保证的,很可能在新建的1000个线程还没有执行完,我们的代码

      System.out.println("运行结果:Counter.count=" + Counter.count);

    就已经执行完了,要想解决这个问题很简单,那就是在最后一句println之前在线程睡眠一段时间,比如睡眠2秒钟。等1000个线程执行完了,在打印"

    "运行结果:Counter.count=" + Counter.count";

    还可以借助于线程辅助类解决,在这里就举例一个最简单的例子展示:

    package face.thread.volatilep;
    
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    public class Counter3 {
    	 
         int count =0;  
        public synchronized  void inc() {
        	count++;
        }
     
        public static void main(String[] args) {
     
            //同时启动1000个线程,去进行i++计算,看看实际结果
        	final Counter3 c = new Counter3();
        	
           final CyclicBarrier cy = new CyclicBarrier(10000, new Runnable() {
      			public void run() {
      		        //这里每次运行的值都有可能不同,可能为1000
      		        System.out.println("运行结果:Counter.count=" + c.count);
      			}
      		});
        	  
            for (int i = 0; i < 10000; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                    	c.inc();
                    	try {
    						cy.await();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					} catch (BrokenBarrierException e) {
    						e.printStackTrace();
    					}
                    }
                }).start();
            }
            
        }
    }


    例子二:原子性自增

        原子是世界上的最小单位,具有不可分割性。比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。Java的concurrent包下提供了一些原子类,我们可以通过阅读API来了解这些原子类的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。
    因为原子性是线程安全的,所以关于原子性自增是不需要传统的加锁技术的,具体看代码:
    package face.thread.volatilep;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class CounterNew2{
    	
    	AtomicInteger count = new AtomicInteger(0);
    
    	public void increment() {
    		count.getAndIncrement();
    	}
    
    	public int getCount() {
    		return count.get();
    	}
    	
    	public static void main(String[] args) {
    		
    		final CounterNew2 cn = new CounterNew2();
    		for(int i = 0 ; i < 10000;i++){
    			new Thread(new Runnable() {
    				public void run() {
    					cn.increment();
    				}
    			}).start();
    		}
    		
    		try {
    			Thread.sleep(1000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("count最终返回值:" + cn.getCount());
    	}
    }
    运行结果也是:10000

     
  • 相关阅读:
    关于ng路由的传参问题(传递一个,多个参数)
    ng指令控制一个元素的影藏的与显示几种方法的使用
    将一个对象push到数组之中的几点问题
    关于ng的路由的几点想法(ui-view)
    angularJS自定义一个过滤器
    ng自带的表单验证
    实现标签的添加与删除(tags)
    关于ng-class,ng-style的用法
    5分钟搞懂:session与cookie
    前端浏览器的两种缓存:协商缓存和强缓存
  • 原文地址:https://www.cnblogs.com/chen1-kerr/p/6900051.html
Copyright © 2011-2022 走看看