Il EDT, Event Dispatch Thread che gestisce la interfaccia utente, giustamente non va mai tenuto "impegnato" per troppo tempo con del proprio codice, quindi per operazioni "lunghe" serve un thread separato.
Se un altro thread deve accedere alla interfaccia utente, deve far "passare" la esecuzione di questi accessi/aggiornamenti nel EDT (il classico invokeLater o invokeAndWait in casi più rari).
Se invece un altro thread deve accedere a model, strutture dati, ecc... che sono anche usati dal EDT (o da altri thread), ci deve essere una sincronizzazione esplicita che garantisca la "mutua esclusione" ma sopratutto la "visibilità" delle modifiche.