多线程设计模式
?
多线程设计模式有很多模式,我用简约的几行伪代码表示吧,如下:
?
模式1:简单的synchronized+wait/notify
最简单的wait/notify的应用,get的时候,如果没有数据就锁住对象,使当前线程等待,当有数据put的时候,调用notify来唤醒等待的线程,释放对象。如下:
private queue;public synchronized Object get(){ while(queue.size<=0){wait()} return queue.remove();}public synchronized void put(Object obj){ queue.put(obj); notifyAll();}?
模式2:synchronized+return
模式2不同于模式1,是get的时候直接返回,线程不等待。如下:
private queue;public synchronized Object get(){ return queue.size<=0? null :queue.remove();}public synchronized void put(Object obj){ queue.put(obj); }?
?
?
模式3:synchronized+wait/notify+buffer
模式3是对模式1的优化,增加了一个“缓存”,当put的时候超过大小需要wait,防止无限制的put操作而导致溢出。
private queue;private count=0;private bufferSize=10;public synchronized Object get(){ while(count<=0)wait(); count--; return queue.remove();}public synchronized void put(Object obj){ while(count>=bufferSize) wait(); count++; queue.put(obj); notifyAll();}?
?
模式4:读写锁
?
?
模式5:new工作线程
? 模式5是在前几个模式的基础上新增加了工作任务线程,当有新请求过来的时候就新建工作线程,如下handle方法:
private queue;private count=0;private bufferSize=10;private synchronized Object get(){ while(count<=0)wait(); count--; return queue.remove();}public synchronized void put(Object obj){ while(count>=bufferSize) wait(); count++; queue.put(obj); notifyAll();}public void handle(){ new Thread(this.get()){ public void run(){ System.out.println("Do work..");}}.start();}?
模式6:用线程池来优化工作线程
?模式5的坏处是每次一个新的工作,需要new一个新的线程来做,这样开销太大,于是引入的“线程池”,如下:
private queue;private count=0;private bufferSize=10;private final max_wk=20;private final WorkerThread[] pool=new WorkerThread[max_wk];private synchronized Object get(){ while(count<=0)wait(); count--; return queue.remove();}public synchronized void put(Object obj){ while(count>=bufferSize) wait(); count++; queue.put(obj); notifyAll();}public void startWrok(){ for(int i=0;i<pool.size;++i){ pool[i]=new WorkerThread(this); pool[i].start(); }}class WorkerThread extends Thread{ private Channel channel; WorkerThread (Channel channel) { this.channel=channel; } public void run() { while(true){ Object obj=channel.get(); obj.doWork(); } }}?
模式7:终止线程
?工作线程在做工作的时候先判断是否需要终止线程。
?
public void stopWork(){ stopWork=true; interrupt();}public void run(){ try{ while(!stopWork){ do something... } }catch( InterruptedException e){ }}模式8:ThreadLocal模式?
?目前很多frame比较经典的保持线程安全的模式,他像一个保险箱一样保管着所有线程对象,他需要做点额外的工作,比如把线程对象set()和get()。
?
?
class RealWork{ public void doSomething(){// 工作 ... }}class Work{ private static final ThreadLocal local=new ThreadLocal(); public void doSomething(){ getReal().doSomething(); } private void getReal(){ // 获取所处当前线程的资源 RealWork obj=local.get(); if(obj==null){ obj=new RealWork(Thread.currentThread().getName()); local.set(obj); } return obj; }} ?
?
?
附录:
transient Thread owner; public boolean put(E o) { if (o == null) throw new NullPointerException(); final AtomicInteger count = this.count;// 大小计数器 if (count.get() == capacity) return false; int c = -1; if (compareAndSetState(0, 1))// 检测当前状态,如果没有线程写,那么保存当前线程 owner = Thread.currentThread(); else acquire(1);// 否则,等待正在写入的线程 try { if (count.get() < capacity) { insert(o); c = count.getAndIncrement(); if (c + 1 < capacity) notFull.signal(); // } } finally { if (tryRelease(1)) { Node h = head; // 等待线程链表 if (h != null && h.waitStatus != 0) unparkSuccessor(h); } } if (c == 0) signalNotEmpty(); return c >= 0; // 精炼的写法 }?
?
在 5.0 以前,锁定的功能是由 Synchronized 关键字来实现的,这样做存在几个问题:
?
public class DaemonThread extends Thread{ public void run(){ while(true){ System.out.println("I'm daemon"); } } public static void main(String args[]){ DaemonThread daemon=new DaemonThread(); daemon.setDaemon(true); daemon.start(); } }
?
?
可以看到JVM很快就退出了,虽然这里是一个while(true)循环。
?