[concurrency-interest] Reference Collections

Peter Firmstone peter.firmstone at zeus.net.au
Thu Jan 5 18:17:53 EST 2012


Just thought I'd better clarify how reads are performed, the Referrer
interface exists to avoid creating unnecessary references, it defines
the equals and hashCode contracts all reference implementations must
follow.

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.river.impl.util;

import java.lang.ref.Reference;

/**
 * An interface for References used in collections, it defines the
equals
 * and hashCode contracts as well as methods identical to Reference.
 * 
 * A client may wish to implement this interface to replace a standard
Referrer
 * during serialisation with custom implementations to deconstruct and
 * reconstruct non serialisable objects, or to perform integrity checks.
 * 
 * This must be implemented in a Collection provided by the client.
 * 
 * After de-serialisation is complete, the client Referrer will be
replaced
 * with a standard Referrer.
 * 
 * @see Reference
 * @see Ref
 * @param <T> 
 * @author Peter Firmstone
 */
public interface Referrer<T> {
    
    /**
     * @see Reference#get()
     */
    public T get() ;
    /**
     * @see Reference#clear()
     */
    public void clear();
    /**
     * @see Reference#isEnqueued() 
     * @return true if enqueued.
     */
    public boolean isEnqueued();
    /**
     * @see Reference#enqueue() 
     * @return 
     */
    public boolean enqueue();
    
    /**
     * Equals is calculated on IDENTITY or equality.
     * 
     * IDENTITY calculation:
     * 
     * if (this == o) return true;
     * if (!(o instanceof Referrer)) return false;
     * Object k1 = get();
     * Object k2 = ((Referrer) o).get();
     * if ( k1 != null && k1 == k2 ) return true;
     * return ( k1 == null && k2 == null && hashCode() == o.hashCode());
     * 
     * Equality calculation:
     * 
     * if (this == o)  return true; // Same reference.
     * if (!(o instanceof Referrer))  return false;
     * Object k1 = get();
     * Object k2 = ((Referrer) o).get();
     * if ( k1 != null && k1.equals(k2)) return true;
     * return ( k1 == null && k2 == null && hashCode() == o.hashCode());
     *
     * @see Ref
     * @param o
     * @return 
     */
    public boolean equals(Object o);
    
    /**
     * Standard hashCode calculation for IDENTITY based references,
where k
     * is the referent.
     * 
     * int hash = 7;
     * hash = 29 * hash + System.identityHashCode(k);
     * hash = 29 * hash + k.getClass().hashCode();
     * 
     * For non IDENTITY references, the hashCode returned is the
referent's 
     * hashCode, after the reference has been cleared, it reverts to the
     * IDENTITY based value.  The IDENTITY hashCode should be calculated
     * at construction time.
     * 
     * @return 
     */
    public int hashCode();
}

Here's an implementation to avoid creating an unnecessary reference:

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.river.impl.util;

/**
 *
 * @author peter
 */
class TempIdentityReferrer<T> implements Referrer<T> {
    
    private final T t;
    
    TempIdentityReferrer(T t){
        if ( t == null ) throw new NullPointerException("Null
prohibited");
        this.t = t;
    }

    @Override
    public T get() {
        return t;
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public boolean isEnqueued() {
        return false;
    }

    @Override
    public boolean enqueue() {
        return false;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        } else if (!(o instanceof Referrer)) {
            return false;
        }
        Object t2 = ((Referrer) o).get();
        return( t == t2 );
    }
    
    public int hashCode(){
        int hash = 7;
        hash = 29 * hash + System.identityHashCode(t);
        hash = 29 * hash + t.getClass().hashCode();
        return hash;
    }
    
}


This is an implementation for a permanent Reference:

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.river.impl.util;

import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

/**
 * Implementation as per Ref.SOFT_IDENTITY
 * 
 * @see Ref#SOFT_IDENTITY
 * @author Peter Firmstone.
 */
class SoftIdentityReferenceKey<T> extends SoftReference<T> implements
Referrer<T>, Serializable{
    private static final long serialVersionUID = 1L;
    private final int hash;

    SoftIdentityReferenceKey(T k, ReferenceQueue<? super T> q) {
        super(k,q);
        int hash = 7;
        hash = 29 * hash + System.identityHashCode(k);
        hash = 29 * hash + k.getClass().hashCode();
        this.hash = hash;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Referrer)) return false;
        Object k1 = get();
        Object k2 = ((Referrer) o).get();
        if ( k1 != null && k1 == k2 ) return true;
        return ( k1 == null && k2 == null && hashCode() ==
o.hashCode());
    }

    @Override
    public int hashCode() {
        return hash;
    }
    
    @Override
    public String toString(){
        Object s = get();
        if (s != null) return s.toString();
        return super.toString();
    }
    
    private Object writeReplace() {
        // returns a Builder instead of this class.
        return ReferenceSerializationFactory.create(get());
    }
    
    private void readObject(ObjectInputStream stream) 
            throws InvalidObjectException{
        throw new InvalidObjectException("Factory required");
    }

}




More information about the Concurrency-interest mailing list