You need to be a bit careful here as you've chosen two different types in your examples. My general rule of thumb is that volatile is best used with booleans and with everything else you probably need some other kind of sync'ing mechanism. It's very common in C# and java to use a volatile boolean to e.g. stop a loop or task executing which has visibility from multiple threads:
class Processor
{
private volatile Boolean _stopProcessing = false;
public void process()
{
do
{ ... }
while (!_stopProcessing);
}
public void cancel()
{
_stopProcessing = true;
}
}
The above would work in C# or java and in this example the volatile keyword means that the read in the process method will be from the actual current value and not a cached value. The compiler or VM may choose to otherwise allow the value to be cached as the loop in process doesn't change _stopProcessing itself.
So the answer is yes to your first question.
Whilst you can use volatile on an int this only helps if you're only ever reading, or writing a single value. As soon as you do anything more complex, e.g. incrementing, you need some other kind of sync'ing such as your usage of Interlocked. In your second example however you are still reading the value of counter without any sync'ing so you're effectively relying on other usages of counter to be sync'ed (e.g. with Interlocked).
In your second example you would still be better off marking your int as volatile, this way you again can be sure that you're getting the current value and not some cached version. However using volatile alone is not enough because the read at the bottom could overlap with a standard decrement (counter--) rather than your correct use of Interlocked.