Run the most recently requested action after finishing current, skip middle tasks
Don't change the locks - You lock on _task, but inside the synchronized block - you change the reference to _task to a new object! This means that if threadA is in the block, threadB is waiting for the lock to release, and threadC calls the method exactly after threadA has run _task = ret; - threadC will be able to enter the block! This makes your lock mechanism fail.

If you want to lock a block - find a lock which defines the scope of your lock - and maintain it accordingly. In your example, the scope seems to be the instance of SingleTaskQueue. Since it is not advisable to do lock(this), create a private object _lock = new object(); and use it as your lock.

Mind your state - in ProcessLastAction you take your action from _action, to take only the last one, but you take the token as a parameter. This means that if two threads queue a new message before the last task finishes - the second _action may be invoked with the first token - which is already cancelled!

If the two objects are dependent of each other - maintain them together. Create a KeyValuePair&lt;CancellationToken, Action&gt; or a custom class to hold them both.

Is that lock necessary? I can't say if you really need the lock, as I don't know how would Task behave if ContinueWith is called twice on it: 


If the last call overrides the previous call (in a thread-safe manner) - you could do away with your whole solution - it could come down to a one-liner :)
If calls are aggregated in an internal queue, and your manual maintenance of the last action is needed, you would have to synchronize your work.


Also, if you have only a single producer thread (only one thread which calls Queue) - you don't need to synchronize.