How do you ensure thread safety when working with shared resources in a multi-threaded Java environment?