To my understanding, lambda expressions capture values, not the variables. For example, the following is a compile-time error:
for (int k = 0; k < 10; k++
The other replies are helpful, but they don't seem to tackle the question directly and answer it in clear terms.
In your first example, you're trying to access k from the lambda expression. The problem here is that k changes its value over time (k++ is called after each loop iteration). Lambda expressions do capture external references, but they need to be marked as final or be "effectively final" (i.e., marking them as final would still produce valid code). This is to prevent concurrency problems; by the time the thread you created is run, k could already hold a new value.
In your second example, on the other hand, the variable you're accessing is arg, which is reinitialized with every iteration of the enhanced for-loop (compare with the example above, where k was merely updated), so you're creating an entirely new variable with each iteration. As an aside, you can also explicitly declare the iteration variable of an enhanced for-loop as final:
for (final Integer arg : listOfInt) {
new Thread(() -> System.out.println(arg)).start();
}
This ensures that the value arg references won't have changed by the time the thread you created is run.