Multithreaded debugging is hard. Make sure you understand what you're getting yourself in to before you begin writing multithreaded code. Do some research to make sure the benefits will outweigh the costs.
Many thread-related bugs won't show up when running the code through the debugger. However, many others will, and the debugger has some useful features (such as the thread view window) for debugging thread problems. Those features aren't perfect, but they're better than nothing.
There are three main types of thread problems: race conditions (where two threads read/write the same variable at the same time), deadlocks (where two threads both wait on each other to finish before proceeding), and starvation (where one thread never gets the chance to run because another thread monopolizes all the CPU time).
There are many different types of synchronization methods. In this chapter, we primarily talked about lock and SyncLock because those are the easiest, but other types (such as ReaderWriterLock) are also useful. Acquaint yourself with as many different synchronization methods as possible because they all have advantages in different situations.
Conditional breakpoints are amazingly powerful—learn to use them. They're especially helpful when debugging multithreaded bugs, but they work for standard single-threaded programs, too.
Deadlocks are "relatively" easy to solve, and several techniques exist for debugging them. Race conditions, however, are much tougher. Logging helps, and freezing some threads in the thread view window helps, but reaching the answer may still take a bit of work.