Java多线程技术-Lock/Condition
2018-06-18 03:47:40来源:未知 阅读 ()
在java1.5中Lock对象来实现同步的效果,而且使用上更方便。
使用ReentrantLock实现同步
public class MyService { private Lock lock = new ReentrantLock(); public void methodA(){ try { lock.lock(); System.out.println("methodA begin threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis()); Thread.sleep(5000); System.out.println("methodA end threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void methodB(){ try { lock.lock(); System.out.println("methodB begin threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis()); Thread.sleep(5000); System.out.println("methodB end threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public class Test { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); new Thread(()->service.methodA()).start(); new Thread(()->service.methodA()).start(); new Thread(()->service.methodB()).start(); new Thread(()->service.methodB()).start(); } }
测试结果:调用lock.lock()的线程就持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢,效果和synchronized一样。
methodA begin threadName=Thread-0 time=1516242293668 methodA end threadName=Thread-0 time=1516242298669 methodA begin threadName=Thread-1 time=1516242298669 methodA end threadName=Thread-1 time=1516242303671 methodB begin threadName=Thread-2 time=1516242303671 methodB end threadName=Thread-2 time=1516242308672 methodB begin threadName=Thread-3 time=1516242308672 methodB end threadName=Thread-3 time=1516242313674
使用Condition实现等待/通知
public class MyService { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void await(){ try { lock.lock(); System.out.println("await时间为"+System.currentTimeMillis()); condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signal(){ try { lock.lock(); System.out.println("signal时间为"+System.currentTimeMillis()); condition.signal(); } finally { lock.unlock(); } } } public class Run { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); new Thread(()->service.await()).start(); Thread.sleep(3000); service.signal(); } }
相似处:
1. 在使用Condition的await方法和signal方法之前比较先调用lock.lock(),否则会抛出异常,跟wait和nofity一样,需在synchronized的代码里运行一样
2. Object.wait() --> Condition.await(). Object.notify()--> Condition.signal(), Object.notifyAll() -->Condition.signalAll()
优点:
在一个Lock对象里面可以创建多个Condition实例,线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度上更加灵活。
使用多个Condition实现通知部分线程
public class MyService { private Lock lock = new ReentrantLock(); private Condition conditionA = lock.newCondition(); private Condition conditionB = lock.newCondition(); public void awaitA(){ try { lock.lock(); System.out.println("begin awaitA时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName()); conditionA.await(); System.out.println("end awaitA时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void awaitB(){ try { lock.lock(); System.out.println("begin awaitB时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName()); conditionB.await(); System.out.println("end awaitB时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signalAll_A(){ try { lock.lock(); System.out.println("signalAll_B 时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName()); conditionA.signalAll(); } finally { lock.unlock(); } } public void signalAll_B(){ try { lock.lock(); System.out.println("signalAll_B 时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName()); conditionB.signalAll(); } finally { lock.unlock(); } } } public class Run { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); new Thread(()->service.awaitA()).start(); new Thread(()->service.awaitB()).start(); Thread.sleep(3000); service.signalAll_A(); } }
测试结果:线程B没有被唤醒
begin awaitA时间为1516244219035Thread name=Thread-0 begin awaitB时间为1516244219036Thread name=Thread-1 signalAll_B 时间为1516244222035Thread name=main end awaitA时间为1516244222035Thread name=Thread-0
生产者和消费者
public class MyList { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private volatile List<String> list = new ArrayList<>(10); public void get() { try { System.out.println("get,listSize="+list.size()); lock.lock(); while (list.size() == 0) { System.out.println("get 等待,ThreadName=" + Thread.currentThread().getName()); condition.await(); } System.out.println("get -1"); list.remove(0); condition.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally{ lock.unlock(); } } public void set() { try { System.out.println("set,listSize="+list.size()); lock.lock(); while (list.size() == 10) { System.out.println("set 等待,ThreadName=" + Thread.currentThread().getName()); condition.await(); } System.out.println("set+1"); list.add("A"); condition.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally{ lock.unlock(); } } } public class Run { public static void main(String[] args) throws InterruptedException { MyList consumer = new MyList(); for(int i =0;i<10;i++){ new Thread(()->{ while(true){ consumer.set();} }).start(); new Thread(()->{ while(true){ consumer.get();} }).start(); } } }
ReentrantReadWriteLock
ReentrantLock具有完全互斥排他的效果,即在同一时间内只有一个线程在执行ReentrantLock.lock()方法后面的任务。但是效率相对低下,而是用ReentrantReadWriteLock读写锁,可以相对提高效率。读写锁也就是有两个锁,一个是和读相关的锁,也称共享锁,一个是和写相关的锁,也叫排它锁。只有读读锁之间不互斥,其他都互斥。
读读锁不互斥的例子
public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read(){ try { lock.readLock().lock(); System.out.println("获得读锁"+Thread.currentThread().getName()+" " + System.currentTimeMillis()); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.readLock().unlock(); } } } public class Run { public static void main(String[] args) throws InterruptedException { Service service = new Service(); new Thread(()->service.read()).start(); new Thread(()->service.read()).start(); } }
测试结果:几乎同时获得读锁,说明它们不互斥的
获得读锁Thread-0 1516246020468
获得读锁Thread-1 1516246020469
读写互斥的例子
public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read(){ try { lock.readLock().lock(); System.out.println("获得读锁"+Thread.currentThread().getName()+" " + System.currentTimeMillis()); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.readLock().unlock(); } } public void write(){ try { lock.writeLock().lock(); System.out.println("获得写锁"+Thread.currentThread().getName()+" " + System.currentTimeMillis()); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.writeLock().unlock(); } } } public class Run { public static void main(String[] args) throws InterruptedException { Service service = new Service(); new Thread(()->service.read()).start(); new Thread(()->service.write()).start(); } }
测试结果:写操作需要等待读锁释放后才能获得
获得读锁Thread-0 1516246209130
获得写锁Thread-1 1516246219132
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:探索java世界中的日志奥秘
下一篇:Eclipse在线安装svn
- 国外程序员整理的Java资源大全(全部是干货) 2020-06-12
- 2020年深圳中国平安各部门Java中级面试真题合集(附答案) 2020-06-11
- 2020年java就业前景 2020-06-11
- 04.Java基础语法 2020-06-11
- Java--反射(框架设计的灵魂)案例 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash