Multithreading can effectively help you achieve higher performance and higher scalability of applications. But be careful when using this technology. This article is the beginning of a series of articles on tools and technical issues related to thread technology. First, I will introduce the thread concept, summarize some common structures, and finally introduce their usage.
Two sides of the thread
Writing multi-threaded programs in Java is not difficult. This is a good thing and a bad thing. When Microsoft developed C #, they copied the ease-of-use dilemma to the entire new platform. At the same time, C # has more program primitives than Java, but the basic java primitives of the thread object and synchronization monitor are sufficient in terms of form and function to provide powerful Thread Programming capabilities. Therefore, be careful before deciding to adopt multithreading technology for applications.
Why not use multithreading?
Remember, when deciding whether to adopt multithreading technology, unless you are playing with code, do not simply use thread-based programming because multithreading programming is cool. Multi-threaded programming is too fashionable. If you are not careful, your boss will be fascinated sooner or later, and then you will die. Second, do not use multithreading easily because it allows the program to run faster, unless you can prove that single-thread implementation is really slow. Finally, before taking the liberty to plunge into the multi-thread mechanism, I would like to recall an apartment model provided by Microsoft, that is, the object is written as a single-threaded structure and runs in a multi-threaded environment. To put it bluntly, you do not have to adopt multi-threaded encoding. However, apartment models are another topic.
If not, multi-threaded programming will inevitably open Pandora's box (meaning it can cause numerous troubles ). The repeatability is not obvious, the program garbage is generated, and the counter is not correctly added. Your application may also be suspended suddenly. For example, a database connection may unexpectedly close or become overloaded. A major headache for advanced developers is to solve the thread problem. These major problems don't take time to solve, and they have a serious negative impact on the product delivery date and product reliability.
Why multithreading?
If your application requires the following operations, you can consider the multithreading mechanism during programming:
- Continuous operations can take a long time to complete.
- Parallel Computing
- It takes a lot of time to wait for the network, file system, user, or other I/O responses
Therefore, make sure that the preceding three situations exist in your application before you start.
If your code runs fast enough, but you think you can make it run faster (assuming you do have this skill), I advise you not to accept this temptation. If you are not sure about the concurrency of the program's computing operations (for example, the concurrent database changes for the same data table-when your database reaches the data table Level Lock), then think about other methods. In addition, if you do not know whether the application spends too much time waiting for input or output, you must first understand the time-consuming situation. In fact, it takes much longer to start three threads to calculate the circumference rate in one thousandth step than to repeat three times in the same thread. Why is this failure? The reason is that, although 2nd Parallel Computing items are indeed available, the designers just ignore the above 3rd standards: There is no idle cycle during a computing period that can be used by parallel computing.
If you are writing a program for a parallel computer equipped with multiple processors, the above rules are exceptional in this case, you can benefit greatly from the software performance through proper parallel operation design-even if each operation is extremely greedy for CPU time.
Basic thread management tools
I have issued a considerable warning for multithreaded programming just now, and also made suggestions for when to use or not to use multithreading. Next I will elaborate on some tools that can be used by multithreaded programming.
Thread object
The. Net Library providesSystem. Threading. ThreadObject, which represents a single thread. You can start the thread and try to complete the task of the thread when the current thread continues running. This is too much help for applications that need to print documents or save large files but want to get user confirmation requests and return control to users. We passProgram ListThis mechanism is demonstrated.
We first created a method: sayhello, which completes our task-display greetings. Its signature must match system. Threading. threadstart (delegate ). Note that the sayhello method is called.Thread. Sleep (INT nummillisecs)Method. This is a very useful structure and will often appear in such examples.
In the main program, we create a new thread by assigning threadstart with the sayhello method and call the start method on the thread. The thread we created is started, and then our main thread continues to run until the end of this example.
In many cases, you may want to execute a slightly different task in each thread. At the same time, you need to pass a parameter from the thread where one task is located to the thread where another task is located. There are several reasonable ways to accomplish this goal. The most direct approach is to createTaskIt stores threads, unique parameters, and providesThreadstartThe assigned worker method. ExploitationWorkerMethod to read the provided parameters, because it is exactlyTaskObject members are of course unique to the thread. By making a thread a public field, you can obtain the permissions to access all the members of the thread without writing additional encapsulation code. SeeProgram list BRead related examples of this technology.
You can even provide a certain return value of the task object by defining fields in the task of saving the thread, and set this return value before the thread completes, finally, after the task is completed, it is read from the thread that starts the task.
You can pause a thread and wait for other threads to complete its tasks. You can perform two operations when you plan to collect the returned results, the above two operations can be used to process data between three separate threads for database update, but do not want to process data until all threads end. The technology is as follows:Program List C.
Here, we use the code of program listing a to create a program. This time we run two threads, each of which completes the same task as before. Call the START () method of two threads and then call their join () method. Calling the join () method on a thread will suspend the execution of the call thread until the end of the called thread. Therefore, the thread1.start () method suspends the main thread until thread1. Then we perform the same operation on thread2. As a result, the main thread is finished only after thread1 and thread2 are completed.
The idea of this example is divided into two parts. First, a thread cannot call the join method on another thread unless the latter has been started. Second, there are more than two forms of join. You can set the timeout time for the call thread to continue running, even if the called thread is still running.
The concept of watchdog is often mentioned in computer science. The so-called watchdog is actually an entity responsible for ensuring functional correctness or processing incorrect functions. Another entity, namely the commonly used watchdog timer, is usually responsible for ensuring that another task is completed on time within a reasonable period of time.Program List DThis shows a simple implementation mechanism for implementing the watchdog timer.
Thread1After the thread is started, the thread is added with a timeout of 10 seconds. BecauseThread1The built-in 15-second pause setting will continue to survive after the expiration time is added. The main thread is tested.Thread1.isaliveIf it is still active, terminate the thread.
Synchronization and monitor
Synchronization is a measure to ensure that only one thread is executing in a single piece of code at a time. The discussion of synchronization technology is beyond the scope of the topic involved in this article, but within a single thread module, for the sake of reliability, there will actually be a large number of structures. However, most of them work normally outside these code blocks most of the time, we have always been familiar with the saying "if it is compiled and obtained the expected answer, it is correct", which is not necessarily true here. This is part of the reason why multithreading is so dangerous.
The monitor is the most basic synchronization structure. Any object has its own associated monitor. One monitor can only be assigned to one object. There is a lock on the monitor, which can be obtained by a unique thread at a certain time. Release the lock before another thread can obtain it. You can declare that an object is visible to all threads to protect a piece of code, such as class fields. You can also obtain an object lock from the monitor before performing an operation, and then release the lock after the operation is complete. An example of this structure is as follows:Program List E.
Here we declare an object mylockobject. The only purpose of this object is to provide a synchronization monitor. The sayhello method allows two threads to print "hello" whenever needed. However, now we useMymonitorobjectThe associated monitor controls the printing of "wonderful" and "world", so that one thread must print twice before being allowed to start printing.
Two other technologies can be used to implement the above Mechanism --Lock ()Key WordsMethodimplattributeAttribute. See examplesProgram list f.
We useLock (...) {... }ReplaceMonitor. Enter (...)AndMonitor. Exit (...)Structure. These structures have the same effect, but the latter is more convenient than the former. We also added a method sayhello2 (), which has the property methodimpl. This attribute specifies all the methods to be synchronized. Essentially, it is equivalent to forcing the call code to obtain the lock on the monitor associated with the type object before the type object containing these synchronous methods is allowed to call the method. This is betterLock ()The encapsulation method code in the statement is much clearer. Note: This attribute is defined in the document as methodimplattril, but its implementation is called methodimpl. According to the declarative attributes, a Microsoft developer may not have noticed this negligence.
Summary
This article covers many issues. I have discussed several reasons for adopting or not using multithreading technology, and also demonstrated some primitive structures used in multithreaded programming. In addition, I introduced the thread object and explained how to run several threads to complete the task, what is a monitor, and how to use the monitor to complete code synchronization. Under specific circumstances, the lock keyword and the methodimpl attribute do the same work.
In subsequent articles, I will continue to describe other basic structures, implement a thread pool, and explore more construction types, such as local thread storage and overlapping I/O.