收藏 分享(赏)

使用jdk并发包构建程序习题与实验.doc

上传人:无敌 文档编号:880583 上传时间:2018-04-30 格式:DOC 页数:19 大小:94KB
下载 相关 举报
使用jdk并发包构建程序习题与实验.doc_第1页
第1页 / 共19页
使用jdk并发包构建程序习题与实验.doc_第2页
第2页 / 共19页
使用jdk并发包构建程序习题与实验.doc_第3页
第3页 / 共19页
使用jdk并发包构建程序习题与实验.doc_第4页
第4页 / 共19页
使用jdk并发包构建程序习题与实验.doc_第5页
第5页 / 共19页
点击查看更多>>
资源描述

1、第 10 章 使用 JDK 并发包构建程序习题与实验目录1. 什么是 CAS? .22. 原子变量类的作用是什么? .23. BlockingQueue 和一般的队列相比有什么特点? .24. ConcurrentMap 有什么特点? .25. 同步器 Semaphore 有什么作用? .26. 同步器 CyclicBarrier 有什么作用? .37. 同步器 CountDownLatch 有什么作用? .38. 同步器 Exchanger 有什么作用? .39. 同步器 Future 有什么作用? .310. ReentrantLock 锁如何使用? .411. ReentrantLock

2、 锁与 Java 内在锁相比有什么特点? .412. (分析)写出下面程序的输出结果(CountDownLatch) 。 .413. (实验)使用 ReentrantLock 与 Condition 实现生产者和消费者问题。 .514. (实验)使用读写锁实现缓存设计 .91. 什么是 CAS?答:CAS,就是 Compare and Swap(比较并交换) , 该操作包含三个操作数 内存位置(V) 、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。类似于 CAS 的指令允许算法执行读-修改- 写操作,而无需害怕其他

3、线程同时修改变量,因为如果其他线程修改变量,那么 CAS 会检测它(并失败) ,算法可以对该操作重新计算。2. 原子变量类的作用是什么?答:Java 的原子变量类提供了“比较并设置”原语。这些原语都是使用平台上可用的最快本机结构来实现的。就是说,原子变量的操作会变为平台提供的用于并发访问的硬件原语,比如比较并交换。原子变量类提供的改变值的方法都是原子性的。从锁转换为原子变量可以降低使用的锁的粒度,把更多的锁请求从竞争变为不竞争,竞争的操作减少,从而提高了吞吐量。3. BlockingQueue 和一般的队列相比有什么特点?答:BlockingQueue 是一个阻塞队列,一种带有一点扭曲的 FI

4、FO 数据结构,不是立即从队列中添加或者删除元素,线程执行操作被阻塞,直到有空间或者元素可用。也可以用于解决生产者消费者问题。4. ConcurrentMap 有什么特点?答:ConcurrentHashMap 实现类只能在键不存在时将元素加入到 map 中,只有在键存在并映射到特定值时才能从 map 中删除一个元素。重要的是这些方法都是原子性的。5. 同步器 Semaphore 有什么作用?答:Semaphore 提供了一个计数信号量,从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能

5、释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。一般操作系统使用 PV 原语控制对有限资源的访问。可以用 Semaphore 进行模拟,P 原语就相当于acquire(),V 原语就相当于 release()。6. 同步器 CyclicBarrier 有什么作用?答:在实际应用中,有时候需要多个线程同时工作以完成同一件事情,而且在完成过程中,往往会等所有线程都到达某一个阶段后再统一执行。这时候 CyclicBarrier 就可以派上用场。它允许一组

6、线程互相等待,直到到达某个公共屏障点。7. 同步器 CountDownLatch 有什么作用?答:CountDownLatch 是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。用给定的数字作为计数器初始化 CountDownLatch。一个线程调用 await()方法后,在当前计数到达零之前,会一直受阻塞。其他线程调用 countDown() 方法,会使计数器递减,所以,计数器的值为 0 后,会释放所有等待的线程。8. 同步器 Exchanger 有什么作用?答:Exchanger 提供了一个同步点,在这个同步点,一对线程可以交换数据。每个线程通过exc

7、hange()方法的入口提供数据给他的伙伴线程,并接收他的伙伴线程提供的数据,并返回。9. 同步器 Future 有什么作用?答:Future 它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get() 方法来获取结果,如有必要,计算完成前可以阻塞此方法。如果在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给 Future 对象在后台完成,当主线程将来需要时,就可以通过 Future 对象获得后台作业的计算结果或者执行状态。10. ReentrantLock 锁如何使用?答:ReentrantLock 锁的使用方法如下:Lock

8、 lock = new ReentrantLock();lock.lock();try / 更新对象状态finally lock.unlock(); Lock 和 synchronized 有一点明显的区别 lock 必须在 finally 块中释放。否则,如果受保护的代码将抛出异常,锁就有可能永远得不到释放。还可以配合 Condition 对象使用。11. ReentrantLock 锁与 Java 内在锁相比有什么特点?答:1)ReentrantLock 必须在 finally 块中释放锁,而使用 synchronized 同步,JVM 将确保锁会获得自动释放。2)与目前的 synchro

9、nized 实现相比,争用下的 ReentrantLock 实现更具可伸缩性。3)对于 ReentrantLock ,可以有不止一个条件变量与它关联。4)允许选择想要一个公平锁,还是一个不公平锁。5)除非您对 Lock 的某个高级特性有明确的需要,或者有明确的证据表明在特定情况下,同步已经成为可伸缩性的瓶颈,否则还是应当继续使用 synchronized。6)Lock 类只是普通的类,JVM 不知道具体哪个线程拥有 Lock 对象。而且,几乎每个开发人员都熟悉 synchronized,它可以在 JVM 的所有版本中工作。12. (分析)写出下面程序的输出结果(CountDownLatch)

10、。package experiment5;import java.util.concurrent.CountDownLatch;public class TestCountDownLatch public static void execute() throws InterruptedException final int n = 3;final CountDownLatch start = new CountDownLatch(1);final CountDownLatch end = new CountDownLatch(n);System.out.print(“A“);Thread t

11、= new Thread() public void run() for (int i = 0; i n; i+) try start.await();/ 此处填空System.out.print(“B“); catch (Exception e) finally end.countDown();/ 此处填空;t.start();System.out.print(“C“);start.countDown();end.await();System.out.print(“D“);public static void main(String args) throws InterruptedExcep

12、tion execute();答:运行结果如下:ACBBBD13. (实验)使用 ReentrantLock 与 Condition 实现生产者和消费者问题。答:Condition 对象一般与 Lock 结合使用,为每个对象提供多个等待集合(wait-set ) 。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。生产者-消费者问题一般是,有一个缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则

13、在有空间变得可用之前,线程将一直阻塞。可以在单独的等待集合中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。下面是缓冲区类:package experiment4;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class BoundedBuffer /

14、可重入锁final Lock lock = new ReentrantLock();/ 两个条件对象final Condition notFull = lock.newCondition();final Condition notEmpty = lock.newCondition();/ 缓冲区final Object items = new Object10;int putptr, takeptr, count;/ 计数器/ 放数据操作,生产者调用该方法public void put(Object x) throws InterruptedException lock.lock();try

15、/ 如果缓冲区满了,则线程等待while (count = items.length)notFull.await();itemsputptr = x;if (+putptr = items.length)putptr = 0;+count;/ 向消费者线程发送通知notEmpty.signal(); finally lock.unlock();/ 消费者线程调用该方法public Object take() throws InterruptedException lock.lock();try / 如果缓冲区空,则等待while (count = 0)notEmpty.await();Obje

16、ct x = itemstakeptr;if (+takeptr = items.length)takeptr = 0;-count;/ 通知其他生产者线程notFull.signal();return x; finally lock.unlock();生产者类:package experiment4;/生产者class Producer implements Runnable BoundedBuffer buffer;public Producer(BoundedBuffer buf) buffer = buf;public void run() char c;for (int i = 0;

17、 i 20; i+) c = (char) (Math.random() * 26 + A);try / 向缓冲区放入数据buffer.put(c); catch (InterruptedException e1) e1.printStackTrace();System.out.println(“Produced: “ + c);try Thread.sleep(int) (Math.random() * 100); catch (InterruptedException e) 消费者类:package experiment4;/消费者class Consumer implements Run

18、nable BoundedBuffer buffer;public Consumer(BoundedBuffer buf) buffer = buf;public void run() Object c = null;for (int i = 0; i 20; i+) try / 取数据c = buffer.take(); catch (InterruptedException e1) e1.printStackTrace();System.out.println(“Consumed: “ + c);try Thread.sleep(int) (Math.random() * 1000); c

19、atch (InterruptedException e) 总测试类:package experiment4;public class LockConditionTest public static void main(String args) BoundedBuffer stack = new BoundedBuffer();/ 创建生产者,消费者Runnable pro1 = new Producer(stack);Runnable con1 = new Consumer(stack);Runnable pro2 = new Producer(stack);Runnable con2 =

20、new Consumer(stack);Thread t1 = new Thread(pro1);Thread t2 = new Thread(con1);Thread t3 = new Thread(pro2);Thread t4 = new Thread(con2);t1.start();t2.start();t3.start();t4.start();运行结果如下:Produced: HConsumed: HProduced: BConsumed: BProduced: YProduced: XProduced: JProduced: ZProduced: QProduced: OPro

21、duced: RProduced: DProduced: NProduced: P14. (实验)使用读写锁实现缓存设计答:ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。在内容管理系统、新闻发布系统等网站的开发设计中,文档的分类(ArticleCategory)一般是极少变化的,并且数据量比较小,读取非常的频繁,可以一次性的把这些文档分类数据从数据库中一次读取出,放入缓存,减少数据库服务器的压力,当数据有变化时,则使缓存失效,然后从新从数据库读取数据。未使用缓存时,主要

22、包含下面的几个类:ArticleCategory:表示文档分类的实体类。CategoryDao:定义访问数据库操作的接口。CategoryDaoImpl:具体访问数据库操作的类,实现了 CategoryDao 接口。Faade:定义了可以使用的业务方法的接口。FacadeImpl:实现了 Faade 接口中的方法。基本工作流程是:客户程序调用 Faade 中定义的业务方法 a,业务方法 a 如果需要访问数据库,调用 CategoryDao 中定义的访问数据库的方法, DAO 中定义的是操作ArticleCategory 实体的方法。在原有系统基础上进行改造,增加对缓存的支持:FullCache

23、:缓存类,管理缓存数据。FacadeCacheProxy:实现了 Faade 接口,其方法的实现又委托给 FacadeImpl 去完成。实现了代理设计模式。FullCacheTest:缓存程序测试类。因为 FacadeCacheProxy 也实现了 Faade 接口,使用缓存后,客户调用业务方法的代码无需改变。这样客户程序无需修改。FacadeCacheProxy 中关于读取文档分类的方法直接从缓存读取,执行其他需要更新数据库的方法时,使缓存失效,从新读取数据库更新后的数据填充缓存。下面是具体的程序:ArticleCategory 类package experiment6;/表示文档分类的实体public class ArticleCategory String id;String name;public String getId() return id;public void setId(String id) this.id = id;public String getName() return name;public void setName(String name) this.name = name;Overridepublic String toString() if (id = null elsereturn id + “/“ + name;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 中等教育 > 职业教育

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报