Thread risks
When running in a multi-threaded environment, you always need to pay attention to some things: you cannot control the thread execution sequence. For example, if you have two threads, thread 1 and thread 2, the CPU may run on thread 1 for a period of time and then switch to thread 2 for a period of time. The problem is that you don't know when the CPU is switched over or how long it will allocate to a thread. The running time of each thread is not fair.
I will give an example to demonstrate the risks caused by the difficulty of thread control. This example includes two threads: thread 1 and thread 2. Thread 1 prints an odd number, and thread 2 prints an even number. These numbers range from 1 to 20. Thread 1 starts first, and then thread 2 starts again. This example will run three times. Listing 6-5 shows the sample code.
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/06342535O-0.png "title =" 18BD0038-B12E-404D-85C3-518D3B8FBE5C.png "/>
As you can see, I first print the odd number and then print the even number. You may expect to see
Print some odd numbers first
Print an odd or even number on average, for example, two odd and two even numbers.
However, these Guesses are incorrect. You can see Table 6-4, which shows the results of three runs.
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/06342550M-1.png "title =" BCE99804-E6E6-43B2-8643-C25F94227911.png "/>
You can see that for 2nd times, 0 is printed first, and the others are printed first. Print odd and even numbers is not average, and there is no indication of how many odd numbers are printed before the even number.
Therefore, in a multi-threaded environment, you cannot control the thread execution sequence. Multithreading is a double-edged sword. Note the following three risks when developing a multi-threaded application.
Security: This standard means that in a multi-threaded environment, the output must be the same as expected. In other words, the program can run multiple times in different sequence, but the final output must be predictable and correct. "Bad Things won't happen ".
Activity: This is different from security. One definition is "some good cases will eventually happen ". For example, if thread A has to wait for the result of thread B, sometimes these results are never returned. Therefore, thread A never calculates the final result. This is usually called a deadlock.
Performance: One of the most important goals of iPhone applications is to have a better performance and a more responsive UI. Therefore, your performance goals must be met. Activity only focuses on some final events; it does not care about how quickly results are obtained.
I will use examples in the following sections to cover every standard, so that you can understand what will lead to a bad result and how you solve it, so that your application has a high performance.
Security
The security requirement is that the program runs in a multi-threaded environment and generates a correct expected result, just like running it in a single-threaded environment. I will discuss a potential problem that often occurs in a multi-threaded environment when two or more threads access the same data at the same time.
Figure 6-5 describes how two threads return the same item and cause the application to crash. In Figure 6-5, thread 1 tries to push the item to the current stack. Then, thread 2 and thread 3 want to fetch the item, and then check to ensure that the item is in this stack. However, after two threads check, thread 2 runs first and then obtains the item. Oops! As you can see, thread 3 has no item to obtain. This will cause your application to crash.
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/0634256319-2.png "title =" 3085A0B3-CC16-47B7-9DAD-B718F1CA8E7F.png "/>
You can get the sample code from the ThreadSafety project, but the Listing 6-6 shows the code annotation for this problem. Note that this problem will not always occur, but it will still happen if you run enough time. The Code uses the NSMutableArray variable for storage, so the client code can add and delete data.
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/0634251C3-3.png "title =" 07F4DD8A-A6EB-4F71-BF80-0B5B7172DABE.png "/>
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/0634256331-4.png "title =" 1CFF9ACA-B9E8-4856-9162-82FF45D2BE28.png "/>
When you run the above Code for a period of time, you will receive the following message:
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/063425Gc-5.png "title =" 93DFA019-EA5C-457E-8C24-143C732AF3B7.png "/>
It tells you that you try to delete objects in an empty array, which should not happen when you have checked the array before deletion. You even print it out to see if it is the last object.
Now, if you look at Figure 6-4 again, you should understand why it crashes-because the first thread has stopped after the first on-site check and printing the last object, the second thread is still running.
Solution
My solution to this problem is to lock this method until the thread finishes running. A lock is a mechanism that ensures that only one thread accesses a specified code block within a period of time. Imagine that you need to compete directly with many people in a single game. You and your competitors have been asked a question, and whoever rings the bell will be able to answer the question first. After the first one is over, another person can ring the bell again. When the first person answers a question, the bell is locked. The same is true for threads. You can create a lock, just like your bell: The first thread that gets the lock is like a rattle) will block all other threads until it ends. After the first thread ends, the lock is opened, which is similar to that of others.) other threads can try to obtain the lock, and this process can be repeated.
The basic concept of the lock mechanism is to ensure that when a thread executes a task, other threads cannot interrupt. For example, if thread 1 obtains the object and prints it out, thread 2 must wait until thread 1 completes execution to obtain and delete the object from the array.
This lock is created on an object. If thread 1 acquires the lock from object A, other threads will no longer be able to obtain the Lock of this object. These threads must wait until thread 1 completes execution and then return the lock to object.
The simplest way to obtain the Lock of object A is to use @ synchronized (objA), as shown in the following Listing 6-7 code.
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/0634255456-6.png "title =" 17216077-9107-4943-A03F-CB9BC7CC6042.png "/>
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/0634255V5-7.png "title =" 0ca12187-3bb4-4820.a263-950f7745e1c4.png "/>
Note: in many cases, the effect of using self as the lock is the same. You only need to make sure that the object you want to lock uses the same object lock. For example, if you have two storage variables, you can consider a single lock for each one.
|
Figure 6-6 shows how the @ synchronized thread works.
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/0634254T1-8.png "title =" BAF3FA32-4F26-4DC6-9505-0F5B7254B104.png "/>
You need to synchronize the push and pop data methods at the same time, because if you lock only one of them, there will still be risks when you pop check, and there will be a lot of data pushed by the memory, but you don't get the object as you want. To prevent this, you need to use lockObj to lock them at the same time, so that only one method is running in a period of time.
Your code is safe, but there are still two more important multi-threaded attributes that need to be discussed.
This article is from the "mobile development" blog, please be sure to keep this source http://ikinglai.blog.51cto.com/6220785/1260681