I would suggest solving the contention problem at the application level. For example, a process would select an entry to work on, update its status to something like 'IN PROGRESS', locking the record momentarily, and then release the lock. Other processes would then skip those records having status 'IN PROGRESS'.
The application-based solution has an advantage of being scalable almost infinitely, whereas the lock-based approach can stop working under some conditions. After all, there's no guarantee that the optimizer chooses index access over a table scan, there's only a probability. Besides, queue tables are usually relatively small and there's a good chance that index won't be used. Even if it is used, it won't be a unique index - more like a range scan: "select ... from queuetable where state = 'WAITING' order by created_ts desc", and the very first process will happily block all others.