The lock statement does NOT "lock code" or any resource that goes in between the curly braces pre se.
I find it best to understand lock from a thread perspective (after all, threading scenarios is when you need to consider locking).
Given your sample code
10 locker = new object();
11 lock (locker)
12 {
...
15 }
When thread X reaches line 10 a new object is created and at line 11 a lock is acquired on the object. Thread X continues to execute whatever code is within the block.
Now, while thread X is in the middle of our block, thread Y reaches line 10. Lo and behold, a new object is created, and since it is created by thread Y no lock is currently acquired on this object. So when thread Y reaches 11 it will successfully acquire a lock on the object and continues to execute the block concurrently with thread X.
This is the situation the lock was suppose to prevent. So what to do?
Make locker a shared object.
01 static object locker = new object();
...
11 lock (locker)
12 {
...
15 }
Now, when thread X reaches line 11 it will acquire the lock and start executing the block. When thread Y reaches line 11 it will try to acquire a lock on the same object as thread X. Since this object is already locked, thread Y will wait until the lock is released. Thus preventing concurrent execution of the code block, thus protecting any resources used by that code to be accessed concurrently.
Note: if other parts of your system should be serialized around the same resources they must all try to lock the same shared locker object.