Todo objeto em java possui um monitor (bloqueio de monitor); quando o thread é executado no código bloqueado por sincronização, ele tenta adquirir o bloqueio de monitor (execute a instrução monitorenter),
Se for adquirido, o contador do bloqueio será incrementado em 1. (o valor inicial é 0.) Quando outros threads desejarem adquirir o bloqueio, eles serão bloqueados até que o thread anterior libere o bloqueio do monitor (execute a instrução monitorexit).
O trabalho de sincronizar a aquisição e liberação de bloqueios é feito pela JVM, e não precisamos fazer isso sozinhos.
Conhecimento relacionado: https://www.cnblogs.com/lycroseup/p/7486860.html