一、多线程程序设计模式的评量标准
1、安全性-不损坏对象
n 对象的字段、状态出现并非预期的情况就是不安全对象
n 1个以上的线程使用而不危及安全性就是线程安全的类
n ArraList与Vector
JDK中就有很多类似这样的非线程安全及线程安全的类,必须针对不同的场景加以利用。在多线 程环境 下,使用线程安全的类可以保证程序的安全性,但是同时会带来一定的性能损耗,所以在非多 线程环境 下,并没有必要去使用线程安全的类。
2、生存性
n 程序一定会进行必要的处理
n 半路停止、不做任何事情,这样没有任何意义
n 安全性与生存性互相抵触,比如死锁
程序一定要有其实现的功能,什么都不做的程序当然是绝对安全的,但是为了实现某些功能而损坏安全性是不明的,要在保证安全性的前提下,尽可能高效地实现功能。
3、复用性
n 程序可再利用
n 可以将共享互斥结构单独封装成可复用的部分
程序应当尽可能地复用,将那些常用的功能单独封装起来,随时供其他地方调用。这点不仅仅是多线程程序应该做的,而是所有程序都应该尽可能做到的。
4、性能
n 快速、大量进行处理
n 指标:数据吞吐量、响应性、容量、效率、可伸缩性等
n 一些指标之间会相互影响,需要根据具体应用场景权衡
高性能一直是程序员追寻的目标,特别是在高并发的程序中。但是程序的性能指标会有很多种,而不同的应用场景,需求是不一样的,必须要权衡利弊,根据特定的业务需求,从而实现相应的性能指标。
5、总结
多线程编程环境下,安全性和生存性是必要条件,这是根本。在这个前提下在去提高复用性和性能,从而提高程序的质量。这些指标,其实是鱼与熊掌难以兼得的关系,必须根据具体环境去实现不同的需求。
二、多线程程序的设计模式
1、Guarded Suspension
n 满足警戒条件才能执行
n 不满足条件及继续wait,直到满足后被唤醒继续操作
n 对于互相影响的操作需要同步
示例代码:
其中的ArrayBlockingQueue的take\put方法都是阻塞的,满足指定条件才能执行完成,否则一直等待。
//请求的包装类
public class Request {
private final String name; public Request(String name) { this.name = name; } public String getName() { return name; } public String toString(){ return "[ Request "+name+" ]"; }
}
//启动线程来创建请求放入队列的类
public class ClientThread extends Thread { private Random random; private ArrayBlockingQueue<Request> requestQueue; public ClientThread(ArrayBlockingQueue requestQueue, String name,long seed){ super(name); this.requestQueue = requestQueue; this.random = new Random(seed); } public void run(){ for (int i=0;i<10000;i++){ Request request = new Request("NO."+i); System.out.println(Thread.currentThread().getName()+" requests "+request); try { requestQueue.put(request); Thread.sleep(random.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }
//启动线程来从队列获取请求的类
public class ServerThread extends Thread { private Random random; private ArrayBlockingQueue<Request> requestQueue; public ServerThread(ArrayBlockingQueue requestQueue, String name, long seed){ super(name); this.requestQueue = requestQueue; this.random = new Random(seed); } public void run(){ for (int i=0;i<10000;i++){ try { Request request = requestQueue.take(); System.out.println(Thread.currentThread().getName()+" take "+request); Thread.sleep(random.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
//测试的main方法
public static void main(String[] args) { ArrayBlockingQueue<Request> queue = new ArrayBlockingQueue<Request>(1);
new ClientThread(queue,"putThread",4325464L).start(); new ServerThread(queue,"takeThread",8454212L).start();
}
2、Read-Write Lock
n 读锁与写锁分开,提高程序性能
n 防止读取与写入的冲突,写入与写入的冲突
n 读取和读取不会冲突,这里可以提高性能
//数据的封装类
public class Data { private final char[] buffer; private final ReadAndWriteLock lock = new ReadAndWriteLock(); public Data(int size){ this.buffer = new char[size]; for(int i=0;i< buffer.length;i++){ buffer[i] = '*'; } } public char[] read()throws InterruptedException { lock.readLock(); try { return doRead(); }finally { lock.readUnlock(); } } public void write(char c)throws InterruptedException{ lock.writeLock(); try{ doWrite(c); }finally { lock.writeUnlock(); } } private char[] doRead(){ char[] newbuf = new char[buffer.length]; for(int i=0 ; i<buffer.length;i++){ newbuf[i] = buffer[i]; } slowly(); return newbuf; } private void doWrite(char c){ //写一个字符slow一下,保证写比读慢 for(int i=0;i<buffer.length;i++){ buffer[i] = c; slowly(); } } private void slowly(){ try { Thread.sleep(50); }catch (InterruptedException e){ } } }
//读线程
public class ReadThread extends Thread { private final Data data; public ReadThread(Data data){ this.data = data; } public void run(){ try{ while(true){ char[] readBuf = data.read(); System.out.println(Thread.currentThread().getName()+"read "+String.valueOf(readBuf)); } }catch (InterruptedException e){ } } }
//写线程
public class WriterThread extends Thread { private static final Random random = new Random(); private final Data data; private final String filler; private int index = 0; public WriterThread(Data data,String filler){ this.data = data; this.filler = filler; } public void run(){ try{ while(true){ char c = nextchar(); data.write(c); Thread.sleep(random.nextInt(3000)); } }catch (InterruptedException e){ } } private char nextchar(){ char c = filler.charAt(index); index++; if(index >= filler.length()){ index = 0; } return c; } }
//读写锁的实现类
public class ReadAndWriteLock { private int readingNum = 0;//实际正在读取的线程数 private int waitingNum = 0;//实际正在等待的线程数 private int writingNum = 0;//实际正在写入的线程数 private boolean preferWrite = true; //优先写入的标志 public synchronized void readLock() throws InterruptedException{ while (writingNum >0 || (preferWrite && waitingNum>0)){ wait(); } readingNum++; } public synchronized void readUnlock(){ readingNum--; preferWrite = true; notifyAll(); } public synchronized void writeLock() throws InterruptedException{ //防止其他线程获取读锁 waitingNum++; try { while (readingNum > 0 || writingNum > 0){ wait(); } }finally { waitingNum--; } //防止其他线程获取写锁 writingNum++; } public synchronized void writeUnlock(){ writingNum--; preferWrite=false; notifyAll(); } }
//测试的main方法
public static void main(String[] args) { Data data = new Data(20);
new ReadThread(data).start(); new ReadThread(data).start(); new ReadThread(data).start(); new ReadThread(data).start(); new ReadThread(data).start(); new WriterThread(data,"123456789abcdefghijklmnopqrstuvwxyz").start(); new WriterThread(data,"ABCDEFGHIJKLMNOPQRSTUVWXYZ").start();
}
3、Future Pattern
n 提升程序的响应性、降低延迟
n 适合不要求操作顺序的情况下使用
n 需要返回值的时候
//结果的抽象类
public interface Result { public abstract String getContent(); }
//结果的实现类
public class RealResult implements Result { private final String content; public RealResult(int count,char c){ System.out.println(" making RealResult(" + count + "," + c + ") BEGIN"); char[] buffer = new char[count]; for(int i=0;i<count;i++){ buffer[i] = c; try{ Thread.sleep(100); }catch (InterruptedException e) { } } System.out.println(" making RealResult(" + count + "," + c + ") END"); this.content = new String(buffer); } @Override public String getContent() { return content; } }
//组合结果实现类的类
public class FutureResult implements Result { private RealResult realResult = null; private boolean ready = false; public synchronized void setRealResult(RealResult realResult){ if(ready){ return; } this.realResult = realResult; this.ready = true; notifyAll(); } @Override public synchronized String getContent() { while(!ready){ try { wait(); }catch (InterruptedException e){ } } return realResult.getContent(); } }
//发起请求的客户端类
public class Client { public Result request(final int count,final char c){ System.out.println("request("+ count +","+c+"start"); final FutureResult futureResult = new FutureResult(); new Thread(){ public void run(){ RealResult realResult = new RealResult(count,c); futureResult.setRealResult(realResult); } }.start(); System.out.println("request("+ count +","+c+"end"); return futureResult; } }
//测试的main方法
public static void main(String[] args) { Client client = new Client();
Result result1 = client.request(10,'X'); Result result2 = client.request(15,'Y'); Result result3 = client.request(20,'Z'); System.out.println(" MAIN JOB START"); try{ Thread.sleep(2000); }catch (InterruptedException e){ } System.out.println(" MAIN JOB END"); System.out.println(" result1 = "+result1.getContent()); System.out.println(" result2 = "+result2.getContent()); System.out.println(" result3 = "+result3.getContent());
}
3、总结
n 模式就是针对某种特殊场景,一直反复发生的问题的解决方案
n 对某个领域问题的解决方法
上面只是介绍了其中3种常见的多线程编程模式,而实际应用中有许多模式可用,不同的场景使用的模式各不相同,需要有的放矢,灵活运用。下图展示了大部分常见的多线程编程模式,及其的侧重点(安全性、生存性、复用性、性能)。
相关推荐
Java并发设计模式是Java开发中不可或缺的一部分,它们用于解决多线程环境下的各种问题,以提高程序的效率、稳定性和可维护性。本教程将深入探讨六个关键的并发设计模式,帮助开发者更好地理解和应用这些模式。 1. *...
本资料“Java并发编程设计原则和模式”深入探讨了如何在Java环境中有效地进行并发处理,以充分利用系统资源并避免潜在的并发问题。 一、并发编程基础 并发是指两个或多个操作在同一时间段内执行,但并不意味着这些...
java 并发变成设计原则与模式第二版 PDF版本,下载即看
4. **并发设计模式**:书中列举并解释了多种并发设计模式,如生产者消费者模式、读写锁模式、双检查锁定模式等。这些模式可以帮助开发者在实际项目中构建高效且稳定的并发系统。 5. **并发集合**:Java并发集合如...
3. **并发设计模式**:书中详细介绍了各种并发设计模式,如生产者消费者模型(BlockingQueue)、读写锁模式(ReadWriteLock)、双检查锁定模式(Double-Checked Locking)、线程池模式(ThreadPoolExecutor)等,...
Java并发编程:设计原则与模式(第二版).pdf
10. **并发模式**:书中可能还会介绍生产者消费者模式、读写锁模式、双端队列模式等经典的并发设计模式,帮助开发者解决实际问题。 通过学习《Java并发编程实战》的源码,你可以更直观地了解这些概念如何在实际代码...
本篇文章将深入探讨相关知识点,包括并发基础、线程安全、同步机制、并发设计模式以及性能优化策略。 1. 并发基础:并发是指多个执行单元(如线程或进程)在同一时间段内执行,但并不意味着它们是并行的。在单核CPU...
这本书涵盖了Java并发编程的核心概念、最佳实践以及常用的设计模式,是提升Java并发编程能力的重要参考资料。 并发编程在现代软件开发中扮演着至关重要的角色,尤其是在服务器端应用和大数据处理中,Java平台因其...
书中还可能包含对并发设计模式的探讨,比如生产者-消费者模式,以及如何利用这些模式来设计高效的并发程序。作者可能还会分享如何测试和调试并发程序,这是并发编程中非常困难且容易被忽视的一部分。包括性能分析、...
3. **并发设计模式**:书里可能讨论了如何使用各种并发设计模式来解决并发问题,比如生产者消费者模型、双检锁(DCL)、读写锁(ReentrantReadWriteLock)等。 4. **并发工具类**:Java并发包(java.util....
4. **并发设计模式** - **生产者-消费者模式** 使用队列作为缓冲区,一个线程生产数据,另一个线程消费数据。 - **读写锁模式** 通过分离读取和写入权限,允许多个读取线程同时进行,但写入时互斥。 - **双检锁/...
7. **并发设计模式**:介绍了一些常见的并发设计模式,如双检锁/双重检查锁定(Double-Checked Locking)、幻读问题解决方案、工作窃取(Work Stealing)等,帮助开发者在实际项目中构建健壮的并发程序。 8. **并发...
本文将深入探讨Java并发编程的设计原则与模式,旨在帮助开发者理解并有效地应用这些原则和模式。 一、并发编程的基础概念 并发是指两个或多个操作在同一时间间隔内执行,而不是严格意义上的同一时刻。在Java中,...
总之,Java并发程序设计是一门深奥且实用的技术,涉及到线程管理、同步机制、并发工具和内存模型等多个方面。通过学习本教程,开发者可以掌握在Java环境中编写高效、可靠的并发程序所需的技能。
我感觉很不错的宝贝,现在和大家分享,希望能够帮到大家,如果你需要可以下载看看,很适合喜欢研究技术的人员
在设计模式方面,本书可能会介绍生产者消费者模式、读写锁模式、工作窃取模式以及线程池模式等。这些模式有助于解决常见的并发问题,例如通过工作队列实现生产者消费者模型,使用读写锁提高读取操作的并行性,利用...
4. **Java并发设计模式** - **生产者消费者模型**:使用BlockingQueue实现线程间的数据共享和同步。 - **读写锁**:ReentrantReadWriteLock允许多个读操作同时进行,但写操作互斥。 - **单例模式**:在多线程环境...
7. **并发设计模式**:书中也会涵盖一些经典的并发设计模式,如生产者消费者模型、读写锁、双检锁等,这些都是解决并发问题的有效工具。 8. **并发异常处理**:在并发环境下,异常处理变得更为复杂,书中有专门章节...