队列:先进先出
1)ArrayBlockingQueue,固定大小队列
当固定大小的队列满了时,可以选择以抛异常(Throws exception)、立马返回判断值(Special value)、阻塞(Blocks)中的1种形式进行操作。如下图。
案例1:有2个线程从队列取数据,有1个线程往队列放数据。
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ArrayBlockTest { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); final BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(3); for(int i=0;i<2;i++){ //有两个线程不停往队列里放数据 final Integer data = i; service.execute(new Runnable() { @Override public void run() { while(true){ try { Thread.sleep((long)(Math.random()*1000)); System.out.println(Thread.currentThread().getName()+"准备放数据"); queue.put(data); //队列如果满了,阻塞在这 System.out.println(Thread.currentThread().getName()+"已经放数据,目前队列数据数:"+queue.size()); } catch (InterruptedException e) { e.printStackTrace(); } } } }); } service.execute(new Runnable() { @Override public void run() { while(true){ try { Thread.sleep(1000); //注释掉看看效果 System.out.println(Thread.currentThread().getName()+"准备取数据"); queue.take(); //取的快,阻塞在这 System.out.println(Thread.currentThread().getName()+"已经取数据,目前队列数据数:"+queue.size()); } catch (InterruptedException e) { e.printStackTrace(); } } } }); } }
案例2:原本使用单线程,要16秒才能完成打印日志,现在启动4个线程分别取打印,只要4秒即可完成。
思路:主线程把任务放到队列里,然后让其他线程自己去取。
//阻塞队列结合线程使用案例 public class ArrayBlockTest2 { public static void main(String[] args) throws InterruptedException { final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(16); //同时开启4个线程去打印,让原来1个线程要打印16s,现在只要打印4s for(int i=0;i<4;i++){ new Thread(new Runnable() { @Override public void run() { while(true){ try { String log = queue.take(); parseLog(log); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } //主线程往队列放16个字符串 for(int i=0;i<16;i++){ final String log = ""+(i+1); queue.put(log); } } public static void parseLog(String log) throws InterruptedException{ System.out.println(log+":"+(System.currentTimeMillis()/1000)); Thread.sleep(1000); //把打印时间设置为1s打印1次 } }