zoukankan      html  css  js  c++  java
  • Java多线程——Lock&Condition

    Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。

    package java_thread;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class LockTest {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		new LockTest().init();
    	}
    	
    	private void init(){
    		final Outputer outputer = new Outputer();
    		new Thread(new Runnable(){
    			@Override
    			public void run() {
    				while(true){
    					try {
    						Thread.sleep(10);
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    					outputer.output("zhangxiaoxiang");
    				}
    				
    			}
    		}).start();
    		
    		new Thread(new Runnable(){
    			@Override
    			public void run() {
    				while(true){
    					try {
    						Thread.sleep(10);
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    					outputer.output("lihuoming");
    				}
    				
    			}
    		}).start();
    		
    	}
    
    	static class Outputer{
    		Lock lock = new ReentrantLock();
    		public void output(String name){
    			int len = name.length();
    			lock.lock();
    			try{
    				for(int i=0;i<len;i++){
    					System.out.print(name.charAt(i));
    				}
    				System.out.println();
    			}finally{
    				lock.unlock();
    			}
    		}
    		
    		public synchronized void output2(String name){
    			int len = name.length();
    			for(int i=0;i<len;i++){
    					System.out.print(name.charAt(i));
    			}
    			System.out.println();
    		}
    		
    		public static synchronized void output3(String name){
    			int len = name.length();
    			for(int i=0;i<len;i++){
    					System.out.print(name.charAt(i));
    			}
    			System.out.println();
    		}	
    	}
    }
    

     

    读写锁:分为读锁写锁多个读锁不互斥读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁

    package java_thread;
    
    import java.util.Random;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class ReadWriteLockTest {
    	public static void main(String[] args) {
    		final Queue3 q3 = new Queue3();
    		for(int i=0;i<3;i++)
    		{
    			new Thread(){
    				public void run(){
    					while(true){
    						q3.get();						
    					}
    				}
    				
    			}.start();
    
    			new Thread(){
    				public void run(){
    					while(true){
    						q3.put(new Random().nextInt(10000));
    					}
    				}			
    				
    			}.start();
    		}
    		
    	}
    }
    
    class Queue3{
    	private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
    	ReadWriteLock rwl = new ReentrantReadWriteLock();
    	public void get(){
    		rwl.readLock().lock();
    		try {
    			System.out.println(Thread.currentThread().getName() + " be ready to read data!");
    			Thread.sleep((long)(Math.random()*1000));
    			System.out.println(Thread.currentThread().getName() + "have read data :" + data);			
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}finally{
    			rwl.readLock().unlock();
    		}
    	}
    	
    	public void put(Object data){
    
    		rwl.writeLock().lock();
    		try {
    			System.out.println(Thread.currentThread().getName() + " be ready to write data!");					
    			Thread.sleep((long)(Math.random()*1000));
    			this.data = data;		
    			System.out.println(Thread.currentThread().getName() + " have write data: " + data);					
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}finally{
    			rwl.writeLock().unlock();
    		}
    		
    	
    	}
    }
    

     读的时候可以被读打断,写的时候不能太打断

    Condition的功能类似在传统线程技术中的Object.wait()和Object.notify()的功能。在等待 Condition 时,允许发生“虚假唤醒”,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为 Condition 应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序程序员总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。

    一个锁内部可以有多个Condition,即有多路等待和通知,可以参看jdk1.5提供的Lock与Condition实现的可阻塞队列的应用案例,从中除了要体味算法,还要体味面向对象的封装。在传统的线程机制中一个监视器对象上只能有一路等待和通知,要想实现多路等待和通知,必须嵌套使用多个同步监视器对象。(如果只用一个Condition,两个放的都在等,一旦一个放的进去了,那么它通知可能会导致另一个放接着往下走。)

    package java_thread;
    
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ConditionCommunication {
    	public static void main(String[] args) {
    		final Business business = new Business();
    		new Thread(
    				new Runnable() {
    					@Override
    					public void run() {
    						for(int i=1;i<=50;i++){
    							business.sub(i);
    						}
    					}
    				}
    		).start();
    		
    		for(int i=1;i<=50;i++){
    			business.main(i);
    		}
    		
    	}
    
    	static class Business {
    		Lock lock = new ReentrantLock();
    		Condition condition = lock.newCondition();
    		private boolean bShouldSub = true;
    		
    		public  void sub(int i){
    			lock.lock();
    			try{
    				while(!bShouldSub){
    					try {
    						condition.await();
    					} catch (Exception e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    				}
    				for(int j=1;j<=5;j++){
    					System.out.println("sub thread sequence of " + j + ",loop of " + i);
    				}
    				bShouldSub = false;
    				condition.signal();
    			}finally{
    				lock.unlock();
    			}
    		}
    		  
    		public  void main(int i){
    			lock.lock();
    			try{
    				while(bShouldSub){
    					try {
    						condition.await();
    					} catch (Exception e) {
    							// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    				}
    				for(int j=1;j<=10;j++){
    					System.out.println("main thread sequence of " + j + ",loop of " + i);
    				}
    				bShouldSub = true;
    				condition.signal();
    			}finally{
    				lock.unlock();
    			}
    		}
    	}
    	
    }
    

     

  • 相关阅读:
    如何计算两个日期之间相差天数
    解决并发问题的小技巧
    Linq实现下拉框绑定
    No DataType in DataTemplate in Windows Phone(二)
    使用TOAD操作oracle初步
    使用log4net记录server Log
    尘世一场烟火
    No DataType in DataTemplate in Windows Phone(—)
    MVC设置初始页时发生的无法找到资源的简单错误
    oracle 使用in的灵异事件
  • 原文地址:https://www.cnblogs.com/tonglin0325/p/6262748.html
Copyright © 2011-2022 走看看