一、多线程程序设计模式的评量标准
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种常见的多线程编程模式,而实际应用中有许多模式可用,不同的场景使用的模式各不相同,需要有的放矢,灵活运用。下图展示了大部分常见的多线程编程模式,及其的侧重点(安全性、生存性、复用性、性能)。
![](https://i-blog.csdnimg.cn/blog_migrate/80abbe904e17f8355ccc301d87fc6349.png)