Welcome to the amazing world of parallel processing. When using threads, no one can guarantee how their progress will be scheduled unless you're using sync mechanism like locks and barriers.
What you're trying to do here is print a single unified output stream, supposedly showing how the threads are progressing. This means you're merging the printouts from the threads, but you can't tell how these prints get interleaved. Furthermore, the prints are not necessarily done in the order the functions are called, there are several layers of buffering, and worse - the actual call to the printing code is not atomically done with the read and the decrement.
You can say that the variable is decremented repeatedly (although since it's not using any atomic/synchronizing mechanism you can't even say for sure that you won't see duplicated results and decrements getting overridden), and each thread will not print a higher value after it printed a lower value alreay, but between threads, the messages can get stalled and therefore print out of order.
When you see in the first example -
Thread-2:the number of tickets is 16
Thread-0:the number of tickets is 19
Thread 0 actually read and decremented the variable first, but the printing got delayed (due to a context switch or anything else). Thread 2 ran after a few other instances already did, but got to print its message right away, and only then did thread 0 get to finish that earlier instance.
Note that you don't see here thread 0 printing any other value in between, its next iteration already reads 14.
Edit: To elaborate a little further, here's a small example of possible interleaving.
Say the machine code for each thread is - (in made up pseudo format)
label:
load [var] -> rax
dec rax
store rax -> [var]
call print function // implicitly uses rax
cmp rax, 0
jg label /// jump-if-greater
(var is a memory location, on the stack for e.g.)
And lets say you have 2 threads running. One possible interleaving could be -
thread 0 | thread 1
------------------------------------
load [var] -> rax | // reads 20
dec rax |
store rax -> [var] |
| load [var] -> rax // reads 19
| dec rax
| store rax -> [var]
| call print function // prints 19
| cmp rax, 0
| jg label
call print function | //prints 20
cmp rax, 0 |
jg label |
it's a little oversimplifying, but it shows how you can get the values printed out of order. Any interleaving is also possible, as long as inside the same thread the order is kept.
Also note that you can have something like
thread 0 | thread 1
------------------------------------
load [var] -> rax | // reads 20
dec rax |
| load [var] -> rax // reads 20 again !!!
| dec rax
| store rax -> [var]
store rax -> [var] |
...
in which case you'll get 20 printed twice.