jjzjj

Java 锁概念在内部是如何工作的?

coder 2023-05-19 原文

Object 类(及其子类)的每个实例都拥有一个锁,该锁在进入 同步 方法时获得,并在退出时自动释放”

这是否意味着我们创建的任何对象实例在内部默认都有一个“锁”(作为字段实现)?

我对这个“锁”概念感到困惑,我想知道它在内部实际上做了什么。

谁能指引我去一些可以找到更多信息的地方?

最佳答案

与往常一样,JLS provides the answer (17.1) :

The most basic of these methods is synchronization, which is implemented using monitors. Each object in Java is associated with a monitor, which a thread can lock or unlock. Only one thread at a time may hold a lock on a monitor. Any other threads attempting to lock that monitor are blocked until they can obtain a lock on that monitor. A thread t may lock a particular monitor multiple times; each unlock reverses the effect of one lock operation.

所以,不,lock 不像 Object 中的字段(您只需查看 Object's source code 即可看到)。相反,每个 Object 都与一个“监视器”相关联,而正是这个监视器被锁定或解锁。

我只是想指出一个进一步的引用资料,其中详细说明了“Java 是如何做到的”,以确保它不会被忽视。这位于@selig 在下面发现的 C++ 代码的注释中,我鼓励所有对下面内容的支持来回答他的问题。您可以在此处提供的链接中查看完整的源代码。

  126 // -----------------------------------------------------------------------------
  127 // Theory of operations -- Monitors lists, thread residency, etc:
  128 //
  129 // * A thread acquires ownership of a monitor by successfully
  130 //   CAS()ing the _owner field from null to non-null.
  131 //
  132 // * Invariant: A thread appears on at most one monitor list --
  133 //   cxq, EntryList or WaitSet -- at any one time.
  134 //
  135 // * Contending threads "push" themselves onto the cxq with CAS
  136 //   and then spin/park.
  137 //
  138 // * After a contending thread eventually acquires the lock it must
  139 //   dequeue itself from either the EntryList or the cxq.
  140 //
  141 // * The exiting thread identifies and unparks an "heir presumptive"
  142 //   tentative successor thread on the EntryList.  Critically, the
  143 //   exiting thread doesn't unlink the successor thread from the EntryList.
  144 //   After having been unparked, the wakee will recontend for ownership of
  145 //   the monitor.   The successor (wakee) will either acquire the lock or
  146 //   re-park itself.
  147 //
  148 //   Succession is provided for by a policy of competitive handoff.
  149 //   The exiting thread does _not_ grant or pass ownership to the
  150 //   successor thread.  (This is also referred to as "handoff" succession").
  151 //   Instead the exiting thread releases ownership and possibly wakes
  152 //   a successor, so the successor can (re)compete for ownership of the lock.
  153 //   If the EntryList is empty but the cxq is populated the exiting
  154 //   thread will drain the cxq into the EntryList.  It does so by
  155 //   by detaching the cxq (installing null with CAS) and folding
  156 //   the threads from the cxq into the EntryList.  The EntryList is
  157 //   doubly linked, while the cxq is singly linked because of the
  158 //   CAS-based "push" used to enqueue recently arrived threads (RATs).
  159 //
  160 // * Concurrency invariants:
  161 //
  162 //   -- only the monitor owner may access or mutate the EntryList.
  163 //      The mutex property of the monitor itself protects the EntryList
  164 //      from concurrent interference.
  165 //   -- Only the monitor owner may detach the cxq.
  166 //
  167 // * The monitor entry list operations avoid locks, but strictly speaking
  168 //   they're not lock-free.  Enter is lock-free, exit is not.
  169 //   See http://j2se.east/~dice/PERSIST/040825-LockFreeQueues.html
  170 //
  171 // * The cxq can have multiple concurrent "pushers" but only one concurrent
  172 //   detaching thread.  This mechanism is immune from the ABA corruption.
  173 //   More precisely, the CAS-based "push" onto cxq is ABA-oblivious.
  174 //
  175 // * Taken together, the cxq and the EntryList constitute or form a
  176 //   single logical queue of threads stalled trying to acquire the lock.
  177 //   We use two distinct lists to improve the odds of a constant-time
  178 //   dequeue operation after acquisition (in the ::enter() epilog) and
  179 //   to reduce heat on the list ends.  (c.f. Michael Scott's "2Q" algorithm).
  180 //   A key desideratum is to minimize queue & monitor metadata manipulation
  181 //   that occurs while holding the monitor lock -- that is, we want to
  182 //   minimize monitor lock holds times.  Note that even a small amount of
  183 //   fixed spinning will greatly reduce the # of enqueue-dequeue operations
  184 //   on EntryList|cxq.  That is, spinning relieves contention on the "inner"
  185 //   locks and monitor metadata.
  186 //
  187 //   Cxq points to the the set of Recently Arrived Threads attempting entry.
  188 //   Because we push threads onto _cxq with CAS, the RATs must take the form of
  189 //   a singly-linked LIFO.  We drain _cxq into EntryList  at unlock-time when
  190 //   the unlocking thread notices that EntryList is null but _cxq is != null.
  191 //
  192 //   The EntryList is ordered by the prevailing queue discipline and
  193 //   can be organized in any convenient fashion, such as a doubly-linked list or
  194 //   a circular doubly-linked list.  Critically, we want insert and delete operations
  195 //   to operate in constant-time.  If we need a priority queue then something akin
  196 //   to Solaris' sleepq would work nicely.  Viz.,
  197 //   http://agg.eng/ws/on10_nightly/source/usr/src/uts/common/os/sleepq.c.
  198 //   Queue discipline is enforced at ::exit() time, when the unlocking thread
  199 //   drains the cxq into the EntryList, and orders or reorders the threads on the
  200 //   EntryList accordingly.
  201 //
  202 //   Barring "lock barging", this mechanism provides fair cyclic ordering,
  203 //   somewhat similar to an elevator-scan.
  204 //
  205 // * The monitor synchronization subsystem avoids the use of native
  206 //   synchronization primitives except for the narrow platform-specific
  207 //   park-unpark abstraction.  See the comments in os_solaris.cpp regarding
  208 //   the semantics of park-unpark.  Put another way, this monitor implementation
  209 //   depends only on atomic operations and park-unpark.  The monitor subsystem
  210 //   manages all RUNNING->BLOCKED and BLOCKED->READY transitions while the
  211 //   underlying OS manages the READY<->RUN transitions.
  212 //
  213 // * Waiting threads reside on the WaitSet list -- wait() puts
  214 //   the caller onto the WaitSet.
  215 //
  216 // * notify() or notifyAll() simply transfers threads from the WaitSet to
  217 //   either the EntryList or cxq.  Subsequent exit() operations will
  218 //   unpark the notifyee.  Unparking a notifee in notify() is inefficient -
  219 //   it's likely the notifyee would simply impale itself on the lock held
  220 //   by the notifier.
  221 //
  222 // * An interesting alternative is to encode cxq as (List,LockByte) where
  223 //   the LockByte is 0 iff the monitor is owned.  _owner is simply an auxiliary
  224 //   variable, like _recursions, in the scheme.  The threads or Events that form
  225 //   the list would have to be aligned in 256-byte addresses.  A thread would
  226 //   try to acquire the lock or enqueue itself with CAS, but exiting threads
  227 //   could use a 1-0 protocol and simply STB to set the LockByte to 0.
  228 //   Note that is is *not* word-tearing, but it does presume that full-word
  229 //   CAS operations are coherent with intermix with STB operations.  That's true
  230 //   on most common processors.
  231 //
  232 // * See also http://blogs.sun.com/dave
  233 
  234 
  235 // -----------------------------------------------------------------------------

关于Java 锁概念在内部是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17368595/

有关Java 锁概念在内部是如何工作的?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  10. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

随机推荐