One concurrent programming pitfall is improper encapsulation leading to races and deadlocks. This can probably happen in lots of different ways, though there are two in particular that I've seen:
Giving variables unnecessarily wide scope. For example, sometimes people declare a variable at instance scope when local scope would do. This can create the potential for races where none need exist.
Exposing locks unnecessarily. If there's no need to expose a lock, then it's consider keeping it hidden away. Otherwise clients may use it and create deadlocks that you could have prevented.
Here's a simple example of #1 above, one that's pretty close to something I saw in production code:
public class CourseService {
private CourseDao courseDao;
private List courses;
public List getCourses() {
this.courses = courseDao.getCourses();
return this.courses;
}
}
In this example there's no need for the courses variable to have instance scope, and now concurrent calls to getCourses() can have races.