zoukankan      html  css  js  c++  java
  • java并发深入

    对象由数据+行为组成。数据就是字段,行为就是方法。
    并发须要保证这些可被多个线程訪问的共享对象数据的完整性,以及某些特定完整性语义。
    比方一个类有一个字段count=0,两个线程同一时候对它做加1操作。


    这时就有可能发生:
     线程1查询到count为1对其加1。
     线程2查询到count为1。对其加1。

      接着线程1提交。线程2提交。
    终于值count还是为1。

    也就是说线程1对count的改动丢失了。

    解决问题。须要加锁。
    java提交了内置锁syncronized。以及Lock。
    内置锁syncronized,利用monitorEnter及monitorExit两条指令保证数据的可见性与原子性。

    比方A类有一个字段count,默认值为0,代码例如以下:
    public class A{
      private int count=0;
     
      public syncronized add(){
         count++;
      }
    }

    线程一首先调用add方法,这时会发生下面步骤:
    1.线程二尝试获取在当前A实例上的锁,没有获取到则堵塞
    2.获取到锁后,将count值从主存拷到当前线程工作内存。这时count为0

    线程二这时运行add方法,但发现获取不到锁。这时堵塞在那边。



    线程一运行完加1后。退出解锁。
    这时线程二就能够获取到锁了。

    并发中对于某些集合,要使它成为同步类,我们常用封装。例如以下:
    class SyncMap{
      Map<String,String> maps=new HashMap<String,String>();
     
      public syncronized V put(K key, V value){
        maps.put(key,value);
      }
    }

    这样做的长处是无论底层maps有无同步。同步策略是什么,都能够安全的实现同步。

    另一种实现同步的方法,即将须要同步的操作交由已经存在的同步类来做。
    考虑上面的count加1操作,假设将count类型改成AtomicInteger,由AtomicInteger实现同步。原子加1操作。



    atomic
    ===============atomic all finish,cost:247,the res:3000000
    ===============atomic all finish,cost:248,the res:3000000
    ===============atomic all finish,cost:262,the res:3000000
    ===============atomic all finish,cost:239,the res:3000000
    ===============atomic all finish,cost:249,the res:3000000

    sync
    ===============sync all finish,cost:54,the res:3000000
    ===============sync all finish,cost:45,the res:3000000
    ===============sync all finish,cost:47,the res:3000000
    ===============sync all finish,cost:45,the res:3000000
    ===============sync all finish,cost:49,the res:3000000

    測试表明上述对于300个线程,每一个线程做10000次加1操作,内置锁syncronized比atomicInteger效率要高

    基本上当并发竞争某个锁非常激烈时,内置锁或者Lock比CAS效率高,原因是当竞争非常激烈时,多个线程做CAS时发现非常难成功。这样浪费了非常多CPU资源。


    測试代码例如以下:

    public class SyncWithAtomicTest {
    	
    	private int count=0;
    	
    	private static final int threadCount=300;
    	
    	private static final int countNum=10000;
    	
    	private final AtomicInteger countAtomicInteger=new AtomicInteger(0);
    
    	private static final ExecutorService threadPool=Executors.newFixedThreadPool(threadCount);
    	
    	private final CountDownLatch latchStart=new CountDownLatch(threadCount);
    	
    	private final CountDownLatch latchEnd=new CountDownLatch(threadCount);
    	
    	public synchronized void addWithCountSync(){
    		for(int i=0;i<countNum;i++){
    			count++;
    		}
    	}
    	
    	public void addWithAtomicCount(){
    		for(int i=0;i<countNum;i++){
    			countAtomicInteger.incrementAndGet();
    		}
    	}
    	
    	public static void main(String[] args) throws InterruptedException {
    		
    		SyncWithAtomicTest obj=new SyncWithAtomicTest();
    		
    		Long oldTime=System.currentTimeMillis();
    		
    		for(int i=0;i<threadCount;i++){
    			CountTask t=new CountTask();
    			t.setTarget(obj);
    			
    			threadPool.execute(t);
    		}
    		
    		obj.latchEnd.await();
    		
    		Long endTime=System.currentTimeMillis()-oldTime;
    		
    //		System.out.println("===============atomic all finish,cost:"+endTime+",the res:"+obj.countAtomicInteger.get());
    		
    		System.out.println("===============sync all finish,cost:"+endTime+",the res:"+obj.count);
    	}
    	
    	static class CountTask implements Runnable{
    		private SyncWithAtomicTest target;
    
    		public void run() {
    			try {
    				target.latchStart.countDown();
    				target.latchStart.await();
    				
    				//we do add oper when all threads is ready 
    				target.addWithCountSync();
    				
    //				target.addWithAtomicCount();
    				
    				System.out.println("thread:"+Thread.currentThread().getId()+",finish the work");
    				
    				target.latchEnd.countDown();
    				
    				
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    				Thread.currentThread().interrupt();
    			}
    		}
    
    		public void setTarget(SyncWithAtomicTest target) {
    			this.target = target;
    		}
    	}
    
    }
    




  • 相关阅读:
    Android下拉刷新-SwipeRefreshLayout,RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout)
    自定义EditText实现一键删除数据
    Androidstudio 点9图报错的问题
    安卓Design包之CoordinatorLayout配合AppBarLayout,ToolBar,TabLaout的使用
    深入了解Hibernate的缓存使用
    跟大牛之间关于hibernate的一些探讨记录
    oracle第一招之神马都是浮云
    大鹏教你如何开发购物网站(里面都是满满的爱)
    JSTL&EL(程序员必看之一)
    动态网页开发
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7372908.html
Copyright © 2011-2022 走看看