In Julia 1.4 you can use $ to copy the current value of x into the macro. I think you see this behavior because the outer while loop has already finish before the thread from Threads.@spawn starts. By than x=3 and gets printed.
function f()
x = 0
@sync while x < 3
Threads.@spawn println($x)
x += 1
end
end