队列(一)

队列:数据的集合,相当于一系列的单元格,可以往单元格里放数据,也可以从单元格里取出数据,但是存取有一条规则:先进先出(就类似于排队,排在前面的先得到服务)。队列有固定大小的,也有不固定大小的。对于固定大小的队列,当队列满时,在往队列中放数据,就会出现阻塞(苦苦等待)或是报错(放不进去了)。

下图是JDK帮助文档中操作BlockingQueue一些常用的方法:

当然这些方法的使用在帮助文档中有详细的解释,在此不再赘述。这些方法也无需记忆,只要记得BlockingQueue,在使用的时候参看帮助文档就可以了。

下面通过代码看一下队列的运行效果。

  • 1-1 一个队列的例子
  •    
       
       
       
    1. import java.util.concurrent.ArrayBlockingQueue; 
    2. import java.util.concurrent.BlockingQueue; 
    3.  
    4. public class BlockingQueueTest { 
    5.     public static void main(String[] args) { 
    6.         //创建一个数组队列,队列里面允许放3个数据 
    7.         final BlockingQueue queue = new ArrayBlockingQueue(3); 
    8.         for(int i=0;i<2;i++){//创建2个线程 
    9.             new Thread(){ 
    10.                 public void run(){ 
    11.                     while(true){ 
    12.                         try { 
    13.                             Thread.sleep((long)(Math.random()*1000)); 
    14.                             System.out.println(Thread.currentThread().getName() + "准备放数据!");                             
    15.                             queue.put(1);//放数据,如果取得慢,就会在此阻塞 
    16.                             System.out.println(Thread.currentThread().getName() + "已经放了数据," +                            
    17.                                         "队列目前有" + queue.size() + "个数据"); 
    18.                         } catch (InterruptedException e) { 
    19.                             e.printStackTrace(); 
    20.                         } 
    21.  
    22.                     } 
    23.                 } 
    24.             }.start(); 
    25.         } 
    26.          
    27.         new Thread(){ 
    28.             public void run(){ 
    29.                 while(true){ 
    30.                     try { 
    31.                         //将此处的睡眠时间分别改为100和1000,观察运行结果 
    32.                         Thread.sleep(1000); 
    33.                         System.out.println(Thread.currentThread().getName() + "准备取数据!"); 
    34.                         queue.take();//取数据,如果取得快,在此阻塞 
    35.                         System.out.println(Thread.currentThread().getName() + "已经取走数据," +                            
    36.                                 "队列目前有" + queue.size() + "个数据");                     
    37.                     } catch (InterruptedException e) { 
    38.                         e.printStackTrace(); 
    39.                     } 
    40.                 } 
    41.             } 
    42.         }.start();           
    43.     } 

上面的代码中,有2个线程从队列里面取数据,有一个线程往队列里面放数据,如果放的比较快,就会出现放数据的线程阻塞;如果取的比较快,取数据的线程就会阻塞。

程序运行的结果如下(部分截图):

程序虽然实现阻塞队列,但是上面的代码还存在一个问题:

  
  
  
  
  1. queue.put(1);//放数据,如果取得慢,就会在此阻塞 
  
  
  
  
  1. queue.take();//取数据,如果取得快,在此阻塞 

以上两行代码虽实现了互斥,但是CPU有可能在刚执行完其中的一行代码时,还没有打印

  
  
  
  
  1. System.out.println(Thread.currentThread().getName() + "已经取走数据," +                            
  2.                                 "队列目前有" + queue.size() + "个数据");     

这样的信息,就去执行另外的操作,即不能保证以下两行代码是原子性的

  
  
  
  
  1. queue.put(1);//放数据,如果取得慢,就会在此阻塞 
  2.                             System.out.println(Thread.currentThread().getName() + "已经放了数据," +                            
  3.                                         "队列目前有" + queue.size() + "个数据"); 

或是

  
  
  
  
  1. queue.take();//取数据,如果取得快,在此阻塞 
  2. System.out.println(Thread.currentThread().getName() + "已经取走数据," +                            
  3.                                 "队列目前有" + queue.size() + "个数据");     

即不能保证程序放进数据就打印信息或是取走数据立即打印信息。

你可能感兴趣的:(java队列)