Java BlockingQueue

BlockingQueue Usage

A BlockingQueue is typically used to have on thread produce objects, which another thread consumes.

The producing thread will keep producing new objects and insert them into the queue, until the queue reaches some upper bound on what it can contain. If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. It remains blocked until a consuming thread takes an object out of the queue.

The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue.

It is not possible to insert null into a BlockingQueue. If you try to insert null, the BlockingQueue will throw a NullPointerException.

It is also possible to access all the elements inside a BlockingQueue, and not just the elements at the start and end. For instance, say you have queued an object for processing, but your application decides to cancel it. You can then call remove(o) to remove a specific object in the queue. However, this is not done very efficiently.

public class BlockingQueueExample {

    public static void main(String[] args) throws Exception {

        BlockingQueue queue = new ArrayBlockingQueue(1024);

        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);

        new Thread(producer).start();
        new Thread(consumer).start();

        Thread.sleep(4000);
    }
}

public class Producer implements Runnable{

protected BlockingQueue queue = null;

public Producer(BlockingQueue queue) {
    this.queue = queue;
}

public void run() {
    try {
        queue.put("1");
        Thread.sleep(1000);
        queue.put("2");
        Thread.sleep(1000);
        queue.put("3");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

ArrayBlockingQueue

ArrayBlockingQueue is a bounded, blocking queue that stores the elements internally in an array. That it is bounded means that it cannot store unlimited amounts of elements. There is an upper bound on the number of elements it can store at the same time. You set the upper bound at instantiation time, and after that it cannot be changed.

The ArrayBlockingQueue stores the elements internally in FIFO order. The head of the queue is the element which has been in queue the longest time, and the tail of the queue is the element which has been in the queue the shortest time.

BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1024);

queue.put("1");

String string = queue.take();

DelayQueue

The DelayQueue blocks the elements internally until a certain delay has expired. The elements must implement the interface java.util.concurrent.Delayed

public interface Delayed extends Comparable<Delayed< {
 public long getDelay(TimeUnit timeUnit);
}   

The value returned by the getDelay() method should be the delay remaining before this element can be released. If 0 or a negative value is returned, the delay will be considered expired, and the element released at the next take() etc. call on the DelayQueue.

LinkedBlockingQueue

The LinkedBlockingQueue keeps the elements internally in a linked structure (linked nodes). This linked structure can optionally have an upper bound if desired. If no upper bound is specified, Integer.MAX_VALUE is used as the upper bound.

The LinkedBlockingQueue stores the elements internally in FIFO order.

BlockingQueue<String> unbounded = new LinkedBlockingQueue<String>();
BlockingQueue<String> bounded   = new LinkedBlockingQueue<String>(1024);

bounded.put("Value");

String value = bounded.take();

PriorityBlockingQueue

The PriorityBlockingQueue is an unbounded concurrent queue. It uses the same ordering rules as the java.util.PriorityQueue class. You cannot insert null into this queue.

All elements inserted into the PriorityBlockingQueue must implement the java.lang.Comparable interface. The elements thus order themselves according to whatever priority you decide in your Comparable implementation.

In case you obtain an Iterator from a PriorityBlockingQueue, the Iterator does not guarantee to iterate the elements in priority order.

BlockingQueue queue   = new PriorityBlockingQueue();
//String implements java.lang.Comparable
queue.put("Value");
String value = queue.take();

SynchronousQueue

The SynchronousQueue is a queue that can only contain a single element internally. A thread inserting an element into the queueis blocked until another thread takes that element from the queue.

Likewise, if a thread tries to take an element and no element is currently present, that thread is blocked until a thread insert an element into the queue.

2016/1/19 posted in  Java

Java线程

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程可以启动多个线程。

线程是指进程中的一个执行流程,一个进程中可以运行多个线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

一个Thread类实例只是一个对象,像Java中的其他任何对象一样,具有变量和方法,生死于堆上。

Java中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着,

当所有用户线程执行完毕的时候,JVM自动关闭。但是守候线程却不独立于JVM,守候线程一般是由操作系统或者用户自己创建的。

每个线程都将启动,每个线程都将运行直到完成。一系列线程以某种顺序启动并比意味着按该顺序执行。对于任何一组启动的线程来说,调度程序不能保证其执行次序,持续时间也无法保证。

在一个CPU的机器上,实际上一次只能运行一个线程。一次只有一个线程栈执行。众多可运行线程中的某一个会被选中作为当前线程。可运行线程被选择运行的顺序是没有保障的。

线程栈是指某时刻内存中线程调度的栈信息,当前调用的方法总是位于栈顶。线程栈的内存是随着程序的运行动态变化的,因此研究线程栈必须选择一个运行的时刻(代码运行到什么地方)

线程的状态转换是线程控制的基础。线程状态总的可分为五大状态:生、死、可运行、运行、等待/阻塞。

  • 新状态:线程对象已经创建,但是还没有在其上调用start()方法
  • 可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时,线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或者睡眠状态回来时,也返回到可运行状态
  • 运行状态:线程调度程序从可运行池中选择一个线程作为当前线程所处的状态。这也是线程进入运行状态的唯一方式。
  • 等待、阻塞、睡眠状态:这是线程有资格运行时它所处的状态。其共同点是:线程仍旧是活的,但是当前没有条件运行。
  • 死亡态:
2016/1/18 posted in  Java

泛型中? super T和? extends T的区别

extend

List<? extends Number> foo3的通配符声明,意味着以下的赋值是合法的:

// Number "extends" Number (in this context)

List<? extends Number> foo3 = new ArrayList<? extends Number>(); 

// Integer extends Number

List<? extends Number> foo3 = new ArrayList<? extends Integer>();

// Double extends Number

List<? extends Number> foo3 = new ArrayList<? extends Double>();
读取操作通过以上给定的赋值语句,你一定能从foo3列表中读取到Number,因为以上的列表要么包含Number元素,要么包含Number的类元素。
你不能保证读取到Integer,因为foo3可能指向的是List<Double>
你不能保证读取到Double,因为foo3可能指向的是List<Integer>
写入操作通过以上给定的赋值语句,你不能往List<? extends T> 中插入任何类型的对象,因为你不能保证列表实际指向的类型是什么。
你不能插入一个Integer元素,因为foo3可能指向List
你不能插入一个Double元素,因为foo3可能指向List

super

// Integer is a "superclass" of Integer (in this context)

List<? super Integer> foo3 = new ArrayList<Integer>();

// Number is a superclass of Integer

List<? super Integer> foo3 = new ArrayList<Number>();

// Object is a superclass of Integer

List<? super Integer> foo3 = new ArrayList<Object>();
读取操作通过以上给定的赋值语句,唯一可以保证的是,你可以读取到Object或者Object子类的对象
写入操作通过以上给定的赋值语句,你可以插入Integer的子类对象,因为Integer的子类同时也是Integer

生产者使用extends

如果你想从列表中读取T类型的元素,你需要把这个列表声明成<? extends T>,但你就不能往该列表中添加任何元素

消费者使用super

如果你想把T类型的元素放入到列表中,你需要把这个列表声明成<? super T>,但你就不能保证从中读取到的元素的类型

即是生产者,也是消费者

如果一个列表即是生产者,又要是消费者,你不能使用泛型通配符声明列表

2016/1/18 posted in  Java

Java线程安全问题之静态变量、实例变量、局部变量

静态变量:非线程安全

静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见。

实例变量:

单例模式线程非安全;非单例模式线程安全

局部变量:

每个线程执行时将会把局部变量放在各自栈帧中,线程件不共享,故不存在线程安全问题

2016/1/18 posted in  Java

Java 单例模式

public class Singleton
{
    private volatile static Singleton singleton = null;
    private Singleton()
    {
    }

    public static Singleton getInstance()
    {
        if (singleton == null) 
        {
            synchronized (Singleton.class) {
                if (singleton == null)
                {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

或者

使用JVM本身机制保证了线程安全问题;由于SingletonHolder是私有的,除了getInstance()之外没有办法访问它,因此它只有在getInstance()被调用时才会真正创建;同时读取实例的时候不会进行同步,没有性能缺陷。

public class Singleton
{
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    private Singleton()
    {
    }

    public static final Singleton getInstance()
    {
        return SingletonHolder.INSTANCE;
    }
}
2016/1/17 posted in  Java