It looks like the purpose of your code is to demonstrate the effect of race condition
. Am I right?
No matter, there is nothing wrong the idea of data exchange with a running thread; and knowing good techniques for that is very important.
My approach is working with the threads created through thread constructors is hiding both thread object and thread method in a thread wrapper
. This techniques has more then one benefit. First of all, the thread method cam be an instance method
(that is, non-static method) of the wrapper. This is the way to avoid ugly parametrized thread start, which is always bad because it requires a type case. With wrapper and an instance method, this is never needed because an the call to the instance method passes "this", a target reference as an implicit first parameter. In case of thread and a thread wrapper, this is the only parameter (as required by the thread constructor) and a reference to the instance of the wrapper. This way, the thread body gets access to all of the members of the wrapper class at once.
More than that, it helps to encapsulate the data accessible by both the wrapped thread and other threads. Making some members private guarantees that the data is used only in a wrapped thread. Other members can be done internal/private and used by more then one thread. If is advisable to provide such access only to the methods and properties. This way, access to the shared data can be synchronized with some thread synchronization primitives, such as
and the like — please see:
What is really important, the use of the thread synchronization objects is hidden inside the wrapper; the objects cannot be misused by the code using the wrapper. Such misuse is a usual problem, so this is yet another considerable benefit.
For a sample code of a thread wrapper, please see my past answers:
How to pass ref parameter to the thread
change paramters of thread (producer) after it started
The code sample in the second answer demonstrates the use of