I came up with this solution which works in my case where I have objects created on multiple threads and are serializable:
public abstract class ObjBase implements Serializable
private static final long serialVersionUID = 1L;
private static final AtomicLong atomicRefId = new AtomicLong();
// transient field is not serialized
private transient long refId;
// default constructor will be called on base class even during deserialization
public ObjBase() {
refId = atomicRefId.incrementAndGet()
}
public long getRefId() {
return refId;
}
}