原先多线程并发编程的学习笔记和代码整理一下贴上来。
---------------------------------
队列
可以使用同步队列来解决任务协作问题,同步队列在任意时刻都只允许一个任务插入或移除元素。
同步队列的实现:
1、java.util.concurrent包中的BlockingQueue接口提供了这个队列,且该接口有大量实现,举例如下:
首先定义一个任务Task类,该任务有3步操作:
class Task{ public enum Status {FIRST,SECOND,THIRD}; private Status status = Status.FIRST; //default private final int id; public Task(int id){ this.id=id; } public void doFirst() throws Exception{ System.out.println("taskId="+id+" doFirst!"); TimeUnit.MILLISECONDS.sleep(1000);//执行第一步操作需要1s status=Status.FIRST; } public void doSecond() throws Exception{ System.out.println("taskId="+id+" doSecond!"); TimeUnit.MILLISECONDS.sleep(200);//执行第二步操作需要0.2s status=Status.SECOND; } public void doThird() throws Exception{ System.out.println("taskId="+id+" doThird!"); TimeUnit.MILLISECONDS.sleep(2000);//执行第三步操作需要2s status=Status.THIRD; } public Status getStatus(){ return status; } public int getId(){ return this.id; } }
然后,对这个task进行处理,每一步都定义一个处理器,这里用到了LinkedBlockingQueue。
第一个任务处理器,启动task,并执行第一步操作doFirst,执行完后放入队列。
class HandlerFirst implements Runnable{ private LinkedBlockingQueue<Task> firstQueue; private int count=0;//任务数 public HandlerFirst(LinkedBlockingQueue<Task> firstQueue){ this.firstQueue=firstQueue; } @Override public void run() { try{ while(!Thread.interrupted()){ Task task=new Task(count++); task.doFirst(); firstQueue.put(task); } }catch(InterruptedException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } }
第二个处理器,从第一步完成的队列中取出任务,然后继续执行第二步操作,完成后再放入第二步完成队列:
class HandlerSecond implements Runnable{ private LinkedBlockingQueue<Task> firstQueue,secondQueue; public HandlerSecond(LinkedBlockingQueue<Task> firstQueue,LinkedBlockingQueue<Task> secondQueue){ this.firstQueue=firstQueue; this.secondQueue=secondQueue; } @Override public void run() { try{ while(!Thread.interrupted()){ Task task = firstQueue.take(); task.doSecond(); secondQueue.put(task); } }catch(InterruptedException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } }
第三步,从完成第二步的队列中取出任务继续处理,之后放入全部完成的队列:
class HandlerThird implements Runnable{ private LinkedBlockingQueue<Task> secondQueue,finishQueue; public HandlerThird(LinkedBlockingQueue<Task> secondQueue,LinkedBlockingQueue<Task> finishQueue){ this.secondQueue=secondQueue; this.finishQueue=finishQueue; } @Override public void run() { try{ while(!Thread.interrupted()){ Task task = secondQueue.take(); task.doThird(); finishQueue.put(task); } }catch(InterruptedException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } }
任务所有步骤都完成时的处理器,打印出taskid:
class FinishHandler implements Runnable{ private LinkedBlockingQueue<Task> finishQueue; public FinishHandler(LinkedBlockingQueue<Task> finishQueue){ this.finishQueue=finishQueue; } @Override public void run() { try{ while(!Thread.interrupted()){ Task task = finishQueue.take(); System.out.println("******* finish! taskId="+task.getId()); } }catch(InterruptedException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } }
最后,测试一下这个程序:
LinkedBlockingQueue<Task> firstQueue=new LinkedBlockingQueue<Task>(), secondQueue=new LinkedBlockingQueue<Task>(), finishQueue=new LinkedBlockingQueue<Task>(); ExecutorService es = Executors.newCachedThreadPool(); es.execute(new HandlerFirst(firstQueue)); es.execute(new HandlerSecond(firstQueue,secondQueue)); es.execute(new HandlerThird(secondQueue,finishQueue)); es.execute(new FinishHandler(finishQueue)); es.shutdown();
定义3个阻塞队列,分别存放第一步、第二步、第三步完成后任务的队列。
然后分别启动他们,任务会不断的创建并将各个步骤完成的结果放入不同的队列中。
由于BlockingQueue内部已经进行了同步处理,所以并发访问时不再需要同步代码。
2、管道
主要就是使用管道流实现该功能:
首相,定义一个Sender,该sender不停的把字符写入流中:
class Sender implements Runnable { private Random rand = new Random(); private PipedWriter out = new PipedWriter(); public PipedWriter getPipedWriter() { return out; } public void run() { while(true) { for(char c = 'A'; c <= 'z'; c++) { try { out.write(c); TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000)); } catch(Exception e) { throw new RuntimeException(e); } } } } }然后定义一个Receiver,不断的从管道中读取数据:
class Receiver implements Runnable { private PipedReader in; public Receiver(Sender sender) throws IOException { in = new PipedReader(sender.getPipedWriter()); } public void run() { try { while(true) { // Blocks until characters are there: System.out.println("Read: " + (char)in.read()); } } catch(IOException e) { throw new RuntimeException(e); } } }最后,测试一下这个程序,首先启动sender,然后启动receiver:
Sender sender = new Sender(); Receiver receiver = new Receiver(sender); ExecutorService es = Executors.newCachedThreadPool(); es.execute(sender); es.execute(receiver);
sender会不停的向管道中写入,receiver不停的从管道中读取,实现了一个队列的功能。