If you have multiple threads potentially inserting identical data into a database, and you need to ensure that only the first succeeds (because its successors don't need to modify the database) you need to ensure that the "check that the data doesn't exist and the write to the database" operation is
atomic - meaning that while it is happening no other thread can interrupt it and start doing the same work.
This is where you must use the lock(lockObj) { /* ... */ } construct, and you must ensure that all your threads use the constrained code.
Here's some
very loose pseudo-code that demonstrates the idea:
namespace ThreadLockPseudoCode
{
class SomeData { }
interface IDatabase
{
bool Contains(SomeData data);
void Write(SomeData data);
}
class Program
{
private readonly object LockObject = new object();
private IDatabase TheDatabase;
private void WriteToDatabase(SomeData dataToWrite)
{
lock(LockObject)
{
if (TheDatabase.Contains(dataToWrite))
return;
TheDatabase.Write(dataToWrite);
}
}
}
}