I found adopting a functional reactive programming really works well for multithreaded systems.
GCD is super great and I use it a lot (...if you had to extend AsyncTask recently: my condolences), but it doesn't safeguard you from race conditions, dealing with locks and all that fun stuff.
This is correct, golang doesn't give you thread safety for free. Values passed via channels are safe as they're implicitly locked (i.e. it's a blocking threadsafe queue), and there are happens-before semantics for starting a goroutine, otherwise you're on your own (explicit locks / atomics / lock-wrappers like sync.WaitGroup). E.g. variable assignment isn't even atomic.
GCD is super great and I use it a lot (...if you had to extend AsyncTask recently: my condolences), but it doesn't safeguard you from race conditions, dealing with locks and all that fun stuff.