多线程模式
single thread execution
single thread execution主要思想是:在同一时刻,对于某一共享资源,只能有一个人访问,即资源同步。
package gate; public class Person { private String name; private String address; public synchronized void setNameAddress(String name,String address){ this.name = name; this.address = address; check(); } private void check(){ if(!name.equals(address)){ System.out.println("problem:"+name+","+address); } } } /*****************************/ package gate; public class RunThread extends Thread { private Person person; private String name; private String address; public RunThread(Person person,String name,String address){ this.person =person; this.name =name; this.address =address; } public void run(){ while(true){ person.setNameAddress(name,address); } } } /*******************************/ package gate; public class Test { public static void main(String[] args) { Person person = new Person(); new RunThread(person,"345","345").start(); new RunThread(person,"456","456").start(); } }
参与者如下:
共享资源(Person ),资源利用者(RunThread)
对于共享资源中的线程非安全方法需要加入锁机制(synchronized或者ReentrantLock)进行同步,确保在某个时间点只有一个线程在访问该方法。
适应的时机:
多线程环境(废话),资源共享(又是废话),资源的状态发生变化(状态不会变化的对象线程安全的)
guarded suspension pattern和productor-consumer pattern
请求发出以后,如果没有准备好的一直等待到数据准备好在返回---》谨慎的等待(恶心的名字)
package guarded; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class Data { private BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(1); public void putRequest(String content){ try { blockingQueue.put(content); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public String getRequest(){ try { return blockingQueue.take(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return ""; } } /*******************************************/ package guarded; import java.util.Random; public class ClientThread extends Thread{ private Data data; public ClientThread(Data data){ this.data =data; } public void run(){ for (int i = 0; i < 1000; i++) { System.out.println("put content:"+i); data.putRequest(String.valueOf(i)); try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /***********************************/ package guarded; import java.util.Random; public class ServerThread extends Thread { private Data data; public ServerThread(Data data){ this.data =data; } public void run(){ while(true){ System.out.println("get content:"+data.getRequest()); try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /**********************************/ package guarded; public class Test { /** * @param args */ public static void main(String[] args) { Data data = new Data(); new ServerThread(data).start(); new ClientThread(data).start(); } }
guarded suspension pattern和productor-comsumer(生产者消费者)很像,这里Data的blockingQueue的容量是1,productor-comsumer则大于一,productor-comsumer也基本上是多对多关系。
jdk1.4以前主要用wait(),notifyAll()进行控制,现在用BlockingQueue更加简单
参与者:
Data(存放资源和等待条件等一系列条件和业务处理的类) ServerThread和ClientThread(处理结果和请求发起的线程)
Read—Write Lock Pattern
Read—Write Lock Pattern将读写分离,在读取之前,获得用来读取的锁,在写在之前,获得用来写入的锁,
读写的锁的关系是:有人读取(多个也无所谓)时,写不能进行;有人写入时,其他的写和读不能进行。
package readwritelock; public class Data { private final char[] buffer; private final ReadWriteLock readWriteLock = new ReadWriteLock(); public Data(int size){ this.buffer=new char[size]; for (int i = 0; i < buffer.length; i++) { buffer[i] ='*'; } } public char[] read(){ readWriteLock.readLock(); try{ return doRead(); }finally{ readWriteLock.readUnLock(); } } public void write(char c){ readWriteLock.writeLock(); try{ doWrite(c); }finally{ readWriteLock.writeUnLock(); } } private char[] doRead(){ try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return buffer; } private void doWrite(char c){ for (int i = 0; i < buffer.length; i++) { buffer[i] =c; } } } /*******************************************/ package readwritelock; public class ReadThread extends Thread { private Data data; public ReadThread(Data data) { this.data = data; } public void run() { while (true) { char[] c = data.read(); System.out.println(Thread.currentThread().getName() + ": " + String.valueOf(c)); } } } /*******************************************/ package readwritelock; public class ReadWriteLock { private volatile int readLocks = 0; private volatile int writeLocks = 0; private volatile int waitLocks = 0; private volatile boolean writeFirst =true; public synchronized void readLock() { // 写锁或者等待锁大于0,读阻塞 while (writeLocks > 0 || writeFirst&&waitLocks > 0) { try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } readLocks++; } public synchronized void readUnLock() { readLocks--; writeFirst =true; notifyAll(); } public synchronized void writeLock() { // 写等待 waitLocks++; try { while (readLocks > 0||writeLocks>0) { wait(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ waitLocks --; } writeLocks++; } public synchronized void writeUnLock() { writeLocks--; writeFirst =false; notifyAll(); } } /*********************************************/ package readwritelock; import java.util.Random; public class WriterThread extends Thread { private Data data; private String str; private int index =0; public WriterThread(Data data, String str) { this.data = data; this.str = str; } public void run(){ while(true){ data.write(get()); try { Thread.sleep(new Random().nextInt(200)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private char get(){ char a =str.charAt(index); index++; if(index>=str.length()){ index = 0; } return a; } } /*********************************************/ package readwritelock; public class Test { public static void main(String[] args) { Data data = new Data(10); new WriterThread(data, "asdsad"); new WriterThread(data, "有亲戚吗"); new ReadThread(data).start(); } }
jdk concurrent 包里面有CurrentHashMap和CopyOnWriteArrayList都有锁的概念
CurrentHashMap有个分离锁,把Map分成几个段,对于一个段的写入,不影响其他段的读写,
CopyOnWriteArrayList可以并发的读取,并且返回一个稳定的迭代器,对于写入,是重新开辟一个数组,拷贝原来的数据进行修改,修改完成后再合并回去.
jdk concurrent的 ReentrantReadWriteLock就是一个可以重入的读写锁