Just an idea: use a db as your 'locking manager'...?
But you can even implement your own locking manager (perhaps as mbean, perhaps with an ejb facade) and deploy it as hasingleton when running with clustered jboss...
We use the same pattern for pessimistic locking. Our implementation requires an extra timestamp column on the table with the row you'd like to lock. We also have a column for the ID of the user who is locking the row for user feedback.
All access to this table (at least the lock columns) must be through an entity bean. Once the entity bean is active in a transaction, you are guaranteed it is not active in any other transactions, unless you mess up the concurrency modifiers for the container (be sure to test this). This allows you to perform an atomic test-and-set operation on the locking row. If the timestamp is null or expired, go ahead and set it for some time in the future (e.g. 20 minutes) granting that user the exclusive lock. Otherwise, fail and report back to the user that the row is in use (optionally, report who owns the lock). There are no singletons or central lock manager so you'll have all the scalability you want.
You'll also want some way of releasing a lock before the expiration time, and we also allow a user to extend their exclusive access. We code defensively on the server side to be sure client applications can never extend or release a lock they don't actually own. It's not trivial, but it works well.
The container's contract that an entity can only be active in a single transaction is the key. Otherwise, you'll end up with a race condition and start granting locks to multiple users in rare (and not easily reproducible) cases.
A word of caution: if you access your entity bean outside a transaction, which I'm sure you would never do, but if you did, then you will not get the atomic behavior you're looking for. To guaranteed the entity is always accessed inside a transaction use trans-attribute=Mandatory in the ejb-jar.xml descriptor.