In Java, a synchronized method is not thread safe if it reads from and writes to one or more static member variables.

Consider:

public class SomeClass {

  static int someCounter = 0;

  synchronized void doSomething() {
    for(int i = 0; i < 20; i++) {
      someCounter++;
      // do something that takes a bit of time, e.g.
      // java.net.InetAddress.getByName("www.wikipedia.org");
      System.out.println("counter="+counter);
    }
  }
}

and assume the access to someCounter is somehow thread safe because of the synchronized keyword on doSomething.
As soon as you call doSomething concurrently on multiple SomeClass instances, it will not print unique numbers. This is because the all instance share the same static member variables. Between the increment of someCounter and printing it, its value might have already changed by another instance.

That particular bug was a bit hidden because a “SomeClass” instance was “cached” in a JEE stateless session bean. Of course the JEE container creates multiple instances of the session bean and hence multiple instances of SomeClass.