原先多线程并发编程的学习笔记和代码整理一下贴上来。
---------------------------------
队列
可以使用同步队列来解决任务协作问题,同步队列在任意时刻都只允许一个任务插入或移除元素。
同步队列的实现:
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不停的从管道中读取,实现了一个队列的功能。