Does an object always see its latest internal state irrespective of thread?

No, this code is not thread-safe because there isn't any happens-before relation between increments made in different threads started with ScheduledExecutorService.

To fix it, you need to either mark the variable as volatile or switch to AtomicInteger or AtomicLong.

UPDATE:

As @BoristheSpider mentioned, in general in case of increment/decrement making a variable volatile is not enough since increment/decrement is not atomic itself and calling it from several threads concurrently will cause race conditions and missed updates. However, in this particular case scheduleWithFixedDelay() guarantees (according to Javadoc) that there will be overlapping executions of scheduled task, so volatile will also work in this particular case even with increment.


Does an object always see its latest internal state irrespective of thread?

Just to be clear for the purposes of this question and its answers, an object doesn't do anything; it's just memory. Threads are the executing entity. It's misleading to say does an object see whatever. It's the thread that's doing the seeing/reading of object state.

This isn't specified in the javadoc, but

Executors.newScheduledThreadPool(5);

returns a ScheduledThreadPoolExecutor.

Your code is using

executorService.scheduleWithFixedDelay(counter, 1, 1, TimeUnit.SECONDS);

The javadoc for ScheduledThreadPoolExecutor#scheduledWithFixedDelay states

Submits a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next.

The class javadoc further clarifies

Successive executions of a periodic task scheduled via scheduleAtFixedRate or scheduleWithFixedDelay do not overlap. While different executions may be performed by different threads, the effects of prior executions happen-before those of subsequent ones.

As such, each execution of Counter#run is guaranteed to see the value of count after it's been incremented by the previous execution. For example, the third execution will read a count value of 2 before it performs its increment.

You don't need volatile or any other additional synchronization mechanism for this specific use case.