新网创想网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
为什么加锁?
创新互联成立于2013年,是专业互联网技术服务公司,拥有项目网站设计制作、成都网站制作网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元射阳做网站,已为上家服务,为射阳各地企业和个人服务,联系电话:028-86922220
面试中有很多时候会问到,为什么加锁?加锁是起到什么作用?
而实际上在我们的开发过程中会出现并发的情况,比如说两个人几乎同时点击了某一个按钮,这个时候就可以简单的理解成并发,那么到底谁先谁后? 程序中就很可能出现错误,当资源出现共享的时候,就会开始涉及到并发了,这个时候我们就可能会用到锁了,来锁住某一个资源,等我用过之后,你才能动。 这就是为什么使用锁。
锁的分类
公平锁/非公平锁
可重入锁
独享锁/共享锁
互斥锁/读写锁
乐观锁/悲观锁
分段锁
偏向锁/轻量级锁/重量级锁
自旋锁
第一次分享,我们就先说这个公平锁和非公平锁。之后会在后序的文章中继续解析!
何为公平?何为非公平?在我们日常生活中的理解不就是对等的就是公平,不对等的就是不公平? 其实差不多的。
公平锁是指多个线程按照申请锁的顺序来获取锁
非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。
在JAVA的代码中什么是公平锁什么又是非公平的锁呢?
一种是使用Java自带的关键字synchronized对相应的类或者方法以及代码块进行加锁,
而另一种是ReentrantLock,前者只能是非公平锁,而后者是默认非公平但可实现公平的一把锁。
上面的类图看起来很不舒服,因为关于ReentrantLock这个锁,确实是没有很好的配图,我们可以自己画出来理解一下
我们先看非公平锁,我画图大家理解一下,就像公共厕所,不要嫌弃恶心,但是绝对容易理解
上面这幅图,加入说图中的管理员是Lock,然后现在A来了,说我要去厕所,这时候管理员一看,厕所没人,那好你进去把,然后A就进去了。
这个时候WC里面是有A的,正在进行式,这时候B来了,B也想去厕所
但是这个时候WC里面是有A的,然后管理员Lock看了一下,里面有人,排队把。。。
然后这B就得憋着,去进入队列去排队,然后又来了个C,这时候A还在里面,C只能也去排队,
就是这个样子的
这时候又过了一小会来了个D,也想去WC,这时候A恰好结束了,
这时候非公平锁就上场了,Lock管理员一看,里面没人,D你进去把,这时候就是这样的。
自旋锁:
是一种用于保护多线程共享资源的锁,与一般互斥锁(mutex)不同之处在于当自旋锁尝试获取锁时以忙等 待(busy waiting)的形式不断地循环检查锁是否可用。当上一个线程的任务没有执行完毕的时候(被锁住), 那么下一个线程会一直等待(不会睡眠),当上一个线程的任务执行完毕,下一个线程会立即执行。
在多 CPU 的环境中,对持有锁较短的程序来说,使用自旋锁代替一般的互斥锁往往能够提高程序的性能。
互斥锁:
当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会进入睡眠状态等待任务执行完毕, 当上一个线程的任务执行完毕,下一个线程会自动唤醒然后执行任务。
总结:
自旋锁会忙等: 所谓忙等,即在访问被锁资源时,调用者线程不会休眠,而是不停循环在那里,直到被锁 资源释放锁。
互斥锁会休眠: 所谓休眠,即在访问被锁资源时,调用者线程会休眠,此时 cpu 可以调度其他线程工 作。直到被锁资源释放锁。此时会唤醒休眠线程。
优缺点:
自旋锁的优点在于,因为自旋锁不会引起调用者睡眠,所以不会进行线程调度,CPU 时间片轮转等耗时操 作。所有如果能在很短的时间内获得锁,自旋锁的效率远高于互斥锁。
缺点在于,自旋锁一直占用 CPU,他在未获得锁的情况下,一直运行--自旋,所以占用着 CPU,如果不 能在很短的时 间内获得锁,这无疑会使 CPU 效率降低。自旋锁不能实现递归调用。
自旋锁:atomic、OSSpinLock、dispatch_semaphore_t
互斥锁:pthread_mutex、@ synchronized、NSLock、NSConditionLock 、NSCondition、NSRecursiveLock
锁的归类
条件锁:就是条件变量,当进程的某些资源要求不满足时就进入休眠,也就
是锁住了。当资源被分配到了,条件锁打开,进程继续运行
NSCondition
NSConditionLock
递归锁:就是同一个线程可以加锁N次而不会引发死锁
NSRecursiveLock
pthread_mutex(recursive)
信号量(semaphore):是一种更高级的同步机制,互斥锁可以说是
semaphore在仅取值0/1时的特例。信号量可以有更多的取值空间,用来实
现更加复杂的同步,而不单单是线程间互斥。
dispatch_semaphore
其实基本的锁就包括了三类 自旋锁 互斥锁 读写锁,
其他的比如条件锁,递归锁,信号量都是上层的封装和实现!
读写锁
读写锁适合于对数据结构的读次数比写次数多得多的情况. 因为, 读模式锁定时可以共享, 以写模式锁住时意味
着独占, 所以读写锁又叫共享-独占锁.
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
成功则返回0, 出错则返回错误编号.
同互斥量以上, 在释放读写锁占用的内存之前, 需要先通过pthread_rwlock_destroy对读写锁进行清理工作, 释
放由init分配的资源.
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
成功则返回0, 出错则返回错误编号.
这3个函数分别实现获取读锁, 获取写锁和释放锁的操作. 获取锁的两个函数是阻塞操作, 同样, 非阻塞的函数为:
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
成功则返回0, 出错则返回错误编号.
非阻塞的获取锁操作, 如果可以获取则返回0, 否则返回错误的EBUSY
读写锁是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同是,它可以分别针对读操作和写操作进行锁定和解锁操作。读写锁遵循的访问控制规则与互斥锁有所不同。在读写锁管辖的范围内,它允许任意个读操作的同时进行。但在同一时刻,它只允许有一个写操作在进行。并且,在某一个写操作被进行的过程中