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

     
  • 相关阅读:
    MQTT TLS 加密传输
    python多进程并发redis
    各种消息队列的特点
    mqtt异步publish方法
    Numpy API Analysis
    Karma install steps for unit test of Angular JS app
    reinstall bower command
    Simulate getter in JavaScript by valueOf and toString method
    How to: Raise and Consume Events
    获取对象的类型信息 (JavaScript)
  • 原文地址:https://www.cnblogs.com/chen1-kerr/p/6900051.html
Copyright © 2011-2022 走看看