Sharing is an essential quality for every good programmer
An NSThread object represents a thread, a lightweight thread operation whose lifecycle is controlled by the programmer and released when the task is completed.
Create and start a thread
There are three ways to create code:
- 1.
alloc init
To create a thread, start the thread manually
- (void)createNewThread1{ //1. Create thread // third argument object: NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@ (run:) object:@"rc"]; Thread. name = @" thread RC"; Thread.threadpriority = 1.0; thread.threadPriority = 1.0; thread.threadPriority = 1.0; /* New thread priority @property NSQualityOfService qualityOfService; NSQualityOfServiceUserInteractive --> Main thread NSQualityOfServiceUserInitiated --> HIGH NSQualityOfServiceUtility --> LOW NSQualityOfServiceBackground --> Background NSQualityOfServiceDefault --> Default */ // thread.qualityOfService = NSQualityOfServiceDefault; //2. Start thread [thread start]; }Copy the code
- 2, separate the child thread, automatically start the thread
-(void)createNewThread2{[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject: @selector]; }Copy the code
- 3. Start a background thread and start automatically
- (void) createNewThread3 {[self performSelectorInBackground: @ the selector (run) withObject: @ "open background threads"]; } -(void)run:(NSString *)param{ NSLog(@"---run----%@---%@",[NSThread currentThread],param); }Copy the code
Print:
RCNSThreadDemo[4644:223899] ---run----<NSThread: 0x600000A98480 >{number = 3, name = thread RC}-- RC RCNSThreadDemo[4644:223901] --run----<NSThread: 0x600000A98A00 >{number = 4, name = (null)}-- Separate child thread RCNSThreadDemo[4644:223902] --run----<NSThread: 0x600000A99740 >{Number = 5, Name = (NULL)}-- Start background threadCopy the code
- Main thread related usage
+ (NSThread *)mainThread; // Get the main thread - (BOOL)isMainThread; + (BOOL)isMainThread; // Whether the thread is the main threadCopy the code
- Get the current thread
NSThread *current = [NSThread currentThread];
Copy the code
Thread state
Threads have five states: New, ready, running, blocked, and dead
- Start thread: Enter ready state -> Run state. The thread enters the dead state automatically when the task is completed
- (void)start;
Copy the code
- Block (pause) a thread: Enters a blocked state
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
Copy the code
- Force a thread to stop: Enter the dead state
+ (void)exit;
Copy the code
Note: Once a thread has stopped (died), the task cannot be started again
Thread safety
The same resource may be shared by multiple threads, that is, multiple threads may access the same resource. For example, multiple threads access the same object, variable, and file. When multiple threads access the same resource, data corruption and data security problems may occur
Analysis chart of security risks provided by Apple:
Thread A and thread B simultaneously read the same address to get 17. Thread A adds 1 to get 18 and then writes. Thread B adds 1 to get 18 and then writes. Apparently, 17 did +1 twice and got 18!! Security concerns arise when multiple threads access the same object with unexpected results. Apple has a solution:
As shown above, when ThreadA adds a lock before accessing a resource, it performs the lock operation. Read the resource, perform the + 1 operation, write the resource, unlock the resource, and perform the UNLOCK operation. During this time, the resource cannot be accessed by any other Thread until the UNLOCK operation is complete. The other threads are in the wait state. Note: locking costs resources.
Check out this article on iOS thread locks and their performance
To paraphrase:
Atomic and non-atomic properties
OC has both nonatomic and atomic options for defining attributes, and presumably most of us use nonatomic
- Atomic: Atomic property, which is essentially locking setter methods (atomic by default). As mentioned above, the thread after locking is safe, but consumes a lot of resources.
- Nonatomic: Non-atomic property, does not lock setter methods, is not thread-safe, suitable for mobile devices with small memory
The recommendation is that all attributes be declared nonatomic; Try to avoid multi-thread snatching the same resource; Try to transfer the service logic of locking and resource snatching to the server to reduce the pressure on mobile clients.
Create 3 threads from 0 to +1 until greater than 10 to stop the code:
@property (nonatomic,assign) NSInteger totalCount; - (void)createSafeThread{ self.threadA = [[NSThread alloc]initWithTarget:self selector:@selector(getTotal) object:nil]; self.threadB = [[NSThread alloc]initWithTarget:self selector:@selector(getTotal) object:nil]; self.threadC = [[NSThread alloc]initWithTarget:self selector:@selector(getTotal) object:nil]; [self.threadA start]; [self.threadB start]; [self.threadC start]; } - (void)getTotal{ while (1) { NSInteger count = self.totalCount; If (count < 10) {for (NSInteger I = 0; i<88888; i++) { NSInteger a = 1; NSInteger b = 1; a = a + b; } self.totalCount = count + 1; NSLog(@"--*-**----%ld",self.totalCount); }else{ break; }}}Copy the code
We would expect to print from 1 to 10, but let’s look at the actual print:
RCNSThreadDemo[1763:182366] ------1 RCNSThreadDemo[1763:182365] ------2 RCNSThreadDemo[1763:182364] ------2 RCNSThreadDemo[1763:182365] ------3 RCNSThreadDemo[1763:182364] ------4 RCNSThreadDemo[1763:182366] ------3 RCNSThreadDemo[1763:182365] ------5 RCNSThreadDemo[1763:182364] ------5 RCNSThreadDemo[1763:182366] ------6 RCNSThreadDemo[1763:182364] ------7Copy the code
It’s easy to see there’s a problem, but it’s even more obvious if you simulate it using GCD. Adding asynchronous tasks to a for loop in a concurrent queue looks like replication, causing bad memory access and program crashes.
Adding a mutex will solve the problem. Here we use:
@synchronized
Use the format: @synchronized {// code to lock}, where the lock object must be unique, generally passing self or a global variable of the current, such as self.threada. Note: locking one piece of code takes only one lock. Multiple locks do not work
Pros and cons of mutex
- Advantages: It can effectively prevent data security problems caused by multi-thread resource grabbing
- Disadvantages: Consumes a lot of CPU resources
Prerequisite: The mutex will cause thread synchronization, that is, multiple threads execute tasks on the same line (in sequence).
The code:
- (void)getTotal{ while (1) { @synchronized (self) { NSInteger count = self.totalCount; If (count < 10) {for (NSInteger I = 0; i<88888; i++) { NSInteger a = 1; NSInteger b = 1; a = a + b; } self.totalCount = count + 1; NSLog(@"------%ld",self.totalCount); }else{ break; }}}}Copy the code
Interthread communication
Common methods of communication between threads
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
Copy the code
Take downloading images as an example:
- (void)downloadImage{ [NSThread detachNewThreadSelector:@selector(download) toTarget:self withObject:nil]; } - (void)download{ NSURL *url = [NSURL URLWithString:@"http://00.minipic.eastday.com/20170227/20170227134901_e45455144ba23b7cee75f292229151b1_21.jpeg"]; NSData *imageData = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:imageData]; WaitUntilDone: whether to wait, // [self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES]; / / the second [self imageView performSelectorOnMainThread: @ the selector (setImage:) withObject: image waitUntilDone: YES]; } // update UI operation -(void)showImage:(UIImage *)image{self.imageview.image = image; NSLog(@"UI----%@",[NSThread currentThread]); }Copy the code
Very simple, start a child thread to download the image, and then go to the main thread to update the UI.
Personal shallow view, wrong place welcome correction