并发(四)
这篇写一个关于BlockingQueue的小例子。
BlockingQueue是阻塞队列,那么什么时候发生阻塞呢?一是队列,入列时没有值进行入列,二是出列时,没有值出列,这样就会发生阻塞。
代码例子如下:
1 class Toast { 2 3 public enum Status { 4 DRY, BUTTERD, JAMMED 5 } 6 7 private Status status = Status.DRY; 8 private final int id; 9 public Toast(int idn) { 10 id = idn; 11 } 12 public void butter() { 13 status = Status.BUTTERD; 14 } 15 public void jam() { 16 status = Status.JAMMED; 17 } 18 public Status getStatus() { 19 return status; 20 } 21 public int getId() { 22 return id; 23 } 24 public String toString(){ 25 return "Toast " + id + ": " + status; 26 } 27 }
1 import java.util.concurrent.LinkedBlockingDeque; 2 3 class ToastQueue extends LinkedBlockingDeque<Toast>{ 4 5 /** 6 * 7 */ 8 private static final long serialVersionUID = 1L; 9 10 11 }
1 import java.util.Random; 2 import java.util.concurrent.TimeUnit; 3 4 public class Toaster implements Runnable { 5 6 private ToastQueue taostQueut; 7 private int count = 0; 8 private Random rand = new Random(47); 9 public Toaster(ToastQueue tq){ 10 taostQueut = tq; 11 } 12 @Override 13 public void run() { 14 15 try { 16 while(!Thread.interrupted()){ 17 TimeUnit.MICROSECONDS.sleep(100 + rand.nextInt(500)); 18 Toast toast = new Toast(count++); 19 System.out.println(toast); 20 taostQueut.put(toast); 21 } 22 }catch (InterruptedException e) { 23 System.out.println("Toaster interrupted"); 24 } 25 System.out.println("Toaster off"); 26 } 27 }
1 public class Jammer implements Runnable { 2 3 private ToastQueue butteredQueue, finishedQueue; 4 public Jammer(ToastQueue butteredQueue, ToastQueue finishedQueue){ 5 this.butteredQueue = butteredQueue; 6 this.finishedQueue = finishedQueue; 7 } 8 @Override 9 public void run() { 10 11 try { 12 while(!Thread.interrupted()){ 13 Toast toast = butteredQueue.take(); 14 toast.jam(); 15 System.out.println(toast); 16 finishedQueue.put(toast); 17 } 18 }catch (InterruptedException e) { 19 System.out.println("Butterer interrupted"); 20 } 21 System.out.println("Butterer off"); 22 } 23 }
1 public class Eatter implements Runnable { 2 3 private ToastQueue finishedQueue; 4 private int counter = 0; 5 public Eatter(ToastQueue tq){ 6 finishedQueue = tq; 7 } 8 @Override 9 public void run() { 10 11 try { 12 while(!Thread.interrupted()){ 13 Toast toast = finishedQueue.take(); 14 if (toast.getId() != counter++ || toast.getStatus() != Toast.Status.JAMMED) { 15 System.out.println(">>>> Eooro: " + toast); 16 System.exit(1); 17 } else { 18 System.out.println("chomp " + toast); 19 } 20 } 21 }catch (InterruptedException e) { 22 System.out.println("Eater interrupted"); 23 } 24 System.out.println("Eater off"); 25 } 26 }
1 import java.util.concurrent.ExecutorService; 2 import java.util.concurrent.Executors; 3 import java.util.concurrent.TimeUnit; 4 5 public class ToastOMatic { 6 7 public static void main(String[] args) throws InterruptedException { 8 9 ToastQueue dryQueue = new ToastQueue(); 10 ToastQueue butteredQueue = new ToastQueue(); 11 ToastQueue finishedQueue = new ToastQueue(); 12 ExecutorService servie = Executors.newCachedThreadPool(); 13 servie.execute(new Toaster(dryQueue)); 14 servie.execute(new Butter(dryQueue, butteredQueue)); 15 servie.execute(new Jammer(butteredQueue, finishedQueue)); 16 servie.execute(new Eatter(finishedQueue)); 17 TimeUnit.SECONDS.sleep(5); 18 servie.shutdownNow(); 19 } 20 21 }
上面组成了一个关于蛋糕摸黄油的小例子,很简单。一条生产线的专门生产蛋糕,另一条生产线是,生产后的蛋糕上抹上黄油,最后摸完黄油的蛋糕,作为成品,可以被吃掉了!
代码中没有显式的使用锁,但是全都在队列的内部进行实现,十分的方便。
今天在使用了alibaba开发规范插件后,发现创建线程池的方法不佳,在此进行记录。以后注意。
ExecutorService servie = Executors.newCachedThreadPool(); 原先是这样创建的。检查后报出如下提示信息
"线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。"
因此,改为如下形式:
ExecutorService servie = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
// user-defined ThreadFactory
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(r.getClass().getName());
return thread;
}
},
// user-defined Thread rejection policy
new ThreadPoolExecutor.AbortPolicy());
自己以后创建线程池的时候会多多注意。