您的位置:首页技术文章
文章详情页

java - 如何理解自旋锁和互斥锁?

【字号: 日期:2023-11-03 13:07:23浏览:66作者:猪猪

问题描述

网上的文章看了很多还是很迷茫,谁能通俗易懂的给我解释一下这两个概念啊?

我在python多线程编码中一般都是在线程的run方法中用while True死循环,然后在死循环的循环体末尾调用queue.task_done移除该队列,然后在主线程调用queue的join方法阻塞主线程,防止主线程直接结束,请问我这种多线程编码方式是否合理?会不会有什么bug?另外请问一下我在run中调用死循环是不是就叫做自旋锁?

问题解答

回答1:

首先要了解什么是互斥锁,互斥锁代表的意思是什么,就是在两个线程A,B 访问同一块内存的时侯。理想情况下我们的执行顺序应该是 A 完全执行完后,B来执行但是,执行是有占用CPU指令时间的,如果不用任何机制的话,当A执行到一半时,B占用了CPU,B去处理这段内存,然后B执行完毕,A再得到CPU,内存数据不就出错了吗?为了内存的数据安全。就采用了一种互斥的技术,A访问这段内存的时候,首先判断这段内存有没有在使用中的标志(取个名字叫做锁),没有的话对这段内存加一个标志(锁),然后A在处理这段内存,A处理完了解锁。如果在A处理内存这个时候B来访问的话,B看到这段内存有使用中的标志(锁)了,B可以有好几种行为。行为一:占用CPU。不断循环并测试锁的状态,线程不会挂起(睡眠),处于忙等状态,采用这种行为的锁叫做自旋锁。行为二:线程B休眠阻塞,放弃CPU,直到A执行完了,锁没了,再使用内存。这种行为叫做互斥锁。看到这里你大概也明白了,锁就是实现互斥作用的同步机制。自旋锁就是互斥锁的一种情况(等待的时候会占用CPU的互斥锁)罢了。不要被名称所误导。要了解背后的机制,换个名字也要明白,参考链接 链接描述

回答2:

1.Python多线程run方法的中使用while循环时,如果在循环体没有使用停止程序机制,会一直运行下去.因此楼主如果想让编码方式得当,可以使用信号量或者其他变量机制通知循环体停止,或者判断队列是否为空,若为空,直接break,退出循环.

2.run中的死循环不是自旋锁,假如循环体内有资源竞争,给加了个锁,但这种锁也是互斥锁.python的锁使用的是信号量semaphore,不是spinlock.

// https://svn.python.org/projects/python/trunk/Python/thread_atheos.hstatic int fastmutex_lock(fastmutex_t * mutex){ atomic_t prev = atomic_add(&mutex->count, 1); if (prev > 0)return lock_semaphore(mutex->sem); return 0;}

自旋锁:多线程同时访问同一个资源,为防止资源的读取修改不一致设置的一种锁,如果线程访问资源时,已经有线程占有资源,那么后者线程会等待当前线程释放资源,此时后者(不休眠)一直运行CPU检测前者占有资源是否释放,这种后者访问并一直检测资源占有的机制就是自旋锁.

互斥锁:目的和自旋锁一样,但机制不一样,当线程占用资源后,加上锁,后者线程访问时,由于资源被占有,转入休眠(sleep)状态,等资源被释放后,通过信号量通知排队等候的线程。

回答3:

Python代码会按照这样的流程进行运行,

设置GIL

切换到某一个线程

运行

线程退出,设置为休眠状态

解锁GIL

重复以上操作

可能是因为GIL的原因,我似乎没有在Python里面看到过自旋锁,更多使用的是互斥锁。

下面是我以前写多线程的方法,仅供参考~

import Queuefrom threading import Threadtemp_queue = Queue.Queue()class Test(Thread): def __init__(self):Thread.__init__(self) def run(self):while temp_queue.empty() is False: pass # do sth here # temp = temp_queue.get()tasks = []for i in range(10): tasks.append(Test())for task in tasks: task.start()for task in tasks: task.join()

既然是队列,Queue中Queue().get()中说明了Remove and return an item from the queue.

标签: java
相关文章: