🧰 Core APIs Toolbox · Intermediate

System & Runtime in Java

currentTimeMillis vs nanoTime, getenv, properties, exit codes.

🧩 The mysteryYou time a task with currentTimeMillis() and get a *negative* duration. Did time go backwards? On your server… it actually can.

Two clocks

**System.currentTimeMillis() is the wall clock: milliseconds since 1970. It can jump when NTP or a user corrects the clock. System.nanoTime() is a monotonic timer with an arbitrary origin: only the difference between two calls** means anything — never use it as a date.

Timing an operation

✗ Wall clock
long t0 = System.currentTimeMillis();
work();
long ms = System.currentTimeMillis() - t0;

If the clock is adjusted mid-way, the result can jump or go negative.

✓ Monotonic timer
long t0 = System.nanoTime();
work();
long ns = System.nanoTime() - t0;

nanoTime never jumps with clock adjustments — the right tool for durations.

Environment vs properties

**System.getenv("HOME") reads an OS environment variable** (null if missing). **System.getProperty("java.version") reads a JVM system property — including ones set with -Dkey=value**. getProperty(key, default) supplies a fallback. Runtime.getRuntime().availableProcessors() tells you the CPU cores.

🔮 Predict it

Missing settings

No -Dapp.color flag was given. What prints?

System.out.println(
    System.getProperty("app.color", "blue"));
System.out.println(
    System.getenv("SURELY_NOT_SET_123"));
  1. null null
  2. blue null
  3. Throws NullPointerException
Show the answer

blue — the default kicks in. null — getenv simply returns null for a variable that doesn't exist.

Exit codes

**System.exit(status) stops the JVM. 0 means success**, any non-zero value means failure — shell scripts and CI pipelines read it to decide what happens next.

🔮 Predict it

Does finally run?

What does this print?

try {
    System.out.println("start");
    System.exit(0);
} finally {
    System.out.println("cleanup");
}
  1. start cleanup
  2. start
  3. cleanup
Show the answer

Only start. System.exit halts the JVM immediately — the finally block never runs (registered shutdown hooks do).

💼 In the real world

Config and ops

Containers configure apps through environment variables (DATABASE_URL), tests flip behaviour with -D properties, and CI fails a build when a tool exits non-zero. Timing code with currentTimeMillis produces weird negative latencies in metrics after clock syncs.

Key takeaways

  1. currentTimeMillis: wall clock, can jump (NTP, user changes)
  2. nanoTime: for elapsed time only, never as a date
  3. getenv reads OS variables; getProperty reads JVM -D properties
  4. System.exit(n) ends the JVM; finally blocks don't run
🤯 Did you know?

System.nanoTime() has nanosecond *precision* but not necessarily nanosecond *accuracy* — its Javadoc only promises it's at least as fine as currentTimeMillis.

Practice questions

Why is subtracting two System.currentTimeMillis() values a risky way to time an operation?

  1. It only has second precision
  2. The wall clock can be adjusted (e.g. by NTP), so the difference can jump or go negative
  3. It counts time spent in other processes
  4. It overflows after 24 days
Check your answer

The wall clock can be adjusted (e.g. by NTP), so the difference can jump or go negative. currentTimeMillis follows the system clock, which can be corrected at any time. nanoTime is monotonic, so it's the right tool for durations.

What does this print?

String mode = System.getProperty("app.mode", "dev");
System.out.println(mode);
System.out.println(System.getenv("NO_SUCH_VAR_42"));
  1. dev null
  2. null null
  3. dev
  4. Throws NullPointerException
Check your answer

dev null. getProperty with a default returns "dev" because no -Dapp.mode was set. getenv simply returns null for a variable that doesn't exist.

Next: IDs that never collide and fingerprints for data — UUIDs and hashing.