In reply to chr_sue:
Have a look at uvm_sequencer_base.svh source code. Both lock() and unlock() call m_lock_req(), just with a different flag. Here is the key code that adds the requested sequence to the queue.
task m_lock_req(..., bit lock);
...
if (lock == 1) begin
// Locks are arbitrated just like all other requests
arb_sequence_q.push_back(new_req);
end else begin
// Grabs are not arbitrated - they go to the front
arb_sequence_q.push_front(new_req);
end
...
endtask