首页 >社区问答列表 >java - 如何理解自旋锁和互斥锁?

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

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

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

  • 小葫芦
  • 小葫芦    2017-06-14 10:53:203楼

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

    +0添加回复

  • 回复
  • 过去多啦不再A梦
  • 过去多啦不再A梦    2017-06-14 10:53:202楼

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

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

    // https://svn.python.org/projects/python/trunk/Python/thread_atheos.h
    static 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)状态,等资源被释放后,通过信号量通知排队等候的线程。

    +0添加回复

  • 回复
  • 过去多啦不再A梦
  • 过去多啦不再A梦    2017-06-14 10:53:201楼

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

    1. 设置GIL

    2. 切换到某一个线程

    3. 运行

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

    5. 解锁GIL

    6. 重复以上操作

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

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

    import Queue
    from threading import Thread
    
    temp_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.

    +0添加回复

  • 回复