The code looks good. Excellent job! I have a few comments about the API.
Ping and Heartbeat are used interchangably.
There are heartbeatReceived & appMessageReceived and pingSent & appMessageSent. In the actual implementations these do the same or very similar things. It would make sense to compress them into one api, and have the type of message received/sent specified by a parameters. Whats more, if a new type of message comes along, the failure detectors will already handle it without each needing to have their code updated.
void messageReceived(String id, long now, MessageType type);
void messageSent(String id, long now, MessageType type);
The getFailedObjects and getObjectsToPing are used to return lists, which in all but one case have contains called on them once and are then discarded. I think these would be better as:
bool isFailed(String id, long now)
bool shouldPing(String id, long now)
a) You don't construct a list which is going to be discarded very soon.
b) The internals of the FailureDetector are better hidden from the user of the API.
In fact, shouldPing could be discarded and getTimeToNextPing(String id, long now) == 0 used.
release should be releaseMonitored to make it symmetrical with registerMonitored.
The failure detection factory could use newInstance to create arbitary failure detectors. So after if (fdName.equals("slicedhb")) fails, you could check if fdName is a fully qualified class name, and if so find the class and create a newInstance. This way its possible to add a failure detector without having to modify the zookeeper code.
There's a lot of duplication in the javadoc for the Zookeeper class. A lot of this could be eliminated by using the @see directive.
FailureDetector.java L131, typo, pint instead of ping.