警告:不要同步线程对象的run()方法,因为 出现多线程需要执行run()的情况。因为 这些线程试图在同一个对象上同步,只有一个 一次线程可以执行run()。结果,每个线程都必须等待 对于先前的线程在它可以访问run()之前终止。
不同的线程如何执行同一run()
个对象的Thread
?
答案 0 :(得分:4)
关于何时进行同步的一些一般性建议似乎与此相关:不要将同步放在线程或runnable中,将它放在线程正在访问的数据结构中。如果使用锁保护数据结构,那么可以确保没有线程可以以不安全的方式访问它,因为数据结构正在强制安全访问。如果将同步保留到线程,那么有人可以编写一个新线程,该线程不执行相应的锁定并可能破坏正在访问的数据结构。请记住,同步点是为了保护数据免受不安全的并发修改。
(如果你看看JavaWorld的文章,清单2和清单3说明了这一点;清单3明显比清单2更清晰,因为FinTrans数据正在保护自己的完整性,其中列表2线程正在进行同步。作者认为列出3具有更好的锁定粒度,并没有解决关于让数据结构保护自己的完整性的观点。也许这是因为他正在掏出玩具的例子并且没有如此严肃地对待它们;毕竟,在他正在使用字符串作为锁定显示页面的顶部,这是一个非常糟糕的主意。)
此外,Java API文档也不鼓励您 锁定线程对象。 Java线程实现锁定线程,例如在加入线程时,所以你所做的任何操作都可能与Java线程API的作用纠缠在一起;例如,如果您尝试锁定线程,那么您所做的任何通知调用都可能会被尝试加入的其他线程占用。此外,您可能会看到一些奇怪的事情,例如,当线程终止时,它会向在其监视器上等待的任何内容发送通知。如果使Thread子类的run方法同步,则运行的线程必须获取自己的锁。如果另一个线程想要加入它(那么除非子类化的线程通过等待放弃锁定)这使得任何线程都无法加入(因为这涉及等待,这需要获取Thread对象上的锁定),所以而不是加入线程暂时获取锁定并等待等待,加入线程可能会在争用锁定的waitset中挂起,直到待连接线程终止。
另一点是,将任务实现为Runnables而不是Thread对象更好。我想不出这样一种情况,即实现Thread对象的run方法比实现Runnable更好,除非我试图故意创建一个令人困惑的情况,或者正在键入一个快速而肮脏的演示。 (我真的很想知道Thread实现Runnable的原因是否能让人们更方便地编写快速的脏代码。)让你的任务成为Runnable可以清楚地表明你有一些没有被束缚的逻辑作为新线程运行,但也可以交给执行者,执行者可以负责该任务的执行方式。 (您可以使用Thread对象执行此操作,但这很令人困惑。)因此,不在Thread对象上创建同步run方法的另一个原因是因为您不应该继承Thread以覆盖run方法(并且通常它是通常最好使用Runnables的执行程序而不是旋转自己的线程)。