All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.xml.ws.transport.tcp.connectioncache.impl.concurrent.ConcurrentQueueNonBlockingImpl Maven / Gradle / Ivy

There is a newer version: 4.0.3
Show newest version
/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package com.sun.xml.ws.transport.tcp.connectioncache.impl.concurrent;

import com.sun.xml.ws.transport.tcp.connectioncache.spi.concurrent.ConcurrentQueue;

public class ConcurrentQueueNonBlockingImpl implements ConcurrentQueue {
    // This implementation of ConcurrentQueue uses a non-blocking algorithm (TBD).
    // For now, this is the same as the blocking impl.
    //
    // Trying to build a lock-free implementation runs into the usual problems:
    // we need to atomically update more than one location at a time in the structure.
    // Short of a transactional memory implementation, we would either need a complicated
    // implementation implementing recursive fixup, or something like the Ladan-Mozes and
    // Shavit algorithm (see "An Optimistic Approach to Lock-Free FIFO Queues" 
    // at http://people.csail.mit.edu/edya/publications/publicationsAndPatents.htm)
    // that delays fixing up one direction in a double linked list.  However, that
    // algorithm does not consider general deletion, and I don't know whether that
    // capability can be easily added or not.
    // Any of these approaches are quite complicated, and so we won't go there yet.
    // As always, first make it work, then make it fast(er), but only if necessary.
    // 
    // Structure: Head points to a node containing a null value, which is a special marker.
    // head.next is the first element, head.prev is the last.  The queue is empty if
    // head.next == head.prev == head.
    final Entry head = new Entry( null ) ;
    final Object lock = new Object() ;
    int count = 0 ;

    private final class Entry {
	Entry next = null ;
	Entry prev = null ;
	private HandleImpl handle ;

	Entry( V value ) {
	    handle = new HandleImpl( this, value ) ;
	}

	HandleImpl handle() {
	    return handle ;
	}
    }

    private final class HandleImpl implements Handle {
	private Entry entry ;
	private final V value ;
	private boolean valid ;

	HandleImpl( Entry entry, V value ) {
	    this.entry = entry ;
	    this.value = value ;
	    this.valid = true ;
	}

	Entry entry() {
	    return entry ;
	}

	public V value() {
	    return value ;
	}

	/** Delete the element corresponding to this handle 
	 * from the queue.  Takes constant time.
	 */
	public boolean remove() {
	    synchronized (lock) {
		if (!valid) {
		    return false ;
		}

		valid = false ;

		entry.next.prev = entry.prev ;
		entry.prev.next = entry.next ;
		count-- ;
	    }

	    entry.prev = null ;
	    entry.next = null ;
	    entry.handle = null ;
	    entry = null ;
	    valid = false ;
	    return true ;
	}
    }

    public int size() {
	synchronized (lock) {
	    return count ;
	}
    }

    /** Add a new element to the tail of the queue.
     * Returns a handle for the element in the queue.
     */
    public Handle offer( V arg ) {
	if (arg == null)
	    throw new IllegalArgumentException( "Argument cannot be null" ) ;

	Entry entry = new Entry( arg ) ;
	
	synchronized (lock) {
	    entry.next = head ;
	    entry.prev = head.prev ;
	    head.prev.next = entry ;
	    head.prev = entry ;
	    count++ ;
	}

	return entry.handle() ;
    }

    /** Return an element from the head of the queue.
     * The element is removed from the queue.
     */
    public V poll() {
	Entry first = null ;

	synchronized (lock) {
	    first = head.next ;
	    if (first == head)
		return null ;
	    else {
		// assert that the following expression returns true!
		first.handle().remove() ;
	    }
	}

	// Once first is removed from the queue, it is invisible to other threads,
	// so we don't need to synchronize here.
	first.next = null ;
	first.prev = null ;
	V value = first.handle().value() ;
	return value ;
    }
} 





© 2015 - 2024 Weber Informatics LLC | Privacy Policy