Да, переключение контекста может определенно произойти.
Именно поэтому при доступе к общему ресурсу важно также заблокировать его из другого потока. Когда поток A заблокирован, поток B не может получить доступ к заблокированному коду.
Например, если два потока запускают следующий код:
1. lock(l);
2. -- change shared resource S here --
3. unlock(l);
Переключение контекста может произойти после шага 1, но другой поток не может удерживать блокировку в это время и, следовательно, не может изменить общий ресурс. Если доступ к общему ресурсу в одном из потоков осуществляется без блокировки - могут случиться плохие вещи!
Что касается расточительности, да, это расточительный метод. Вот почему существуют методы, которые пытаются вообще избежать блокировок. Эти методы называются без блокировки , и некоторые из них основаны на службах сильной блокировки, таких как CAS (Сравнение и замена) или другие.