我们以前已经谈到过多线程线程的实现,但是线程开发不仅像线程一样简单。线程的实现只是多线程开发的第一步。实施线程后,我们还需要确保线程操作的安全性和效率。不安全的线程实现可能会导致程序运行结果错误,并且还可能导致程序永久卡死亡,这是致命的锁定。问题,我们需要了解线程安全性是什么。
线程安全性经常在工作中提到。例如,您的对象不安全,线程运行结果是错误的。尽管经常提到线程安全性,但我们可能没有明确的线程安全性定义。那么线程安全是什么?
Brian Goetz是“ Java并发实践中的Java”的作者,他了解线程的安全性。当多个线程访问对象时,如果您不需要考虑在运行时环境中这些线程的调度和交替实现,则无需执行其他添加添加,并且调用此对象的行为可以获得正确的结果,然后此对象是线程-SAFE。
布莱恩·戈兹(Brian Goetz)想要表达的是,如果此对象是安全的,则无需将其称为线程安全的对象。
在我们的实际开发过程中,我们经常遇到不安全的线程。在这里,我们介绍了三个典型的线程安全问题。
线程创建和启动引起的线程安全问题是创建对象并发布和初始化其他类或对象的常见操作。但是,如果我们操作的时间或地点是错误的,则可能会导致线程安全问题。如代码所示:
我们创建一个共享变量列表。主函数创建并启动线程。在线程中,它初始化并将元素添加到列表中,并将结果打印在主线程中。想象现在会发生什么?实际上,空中指针异常或数组交叉-Border。
这就是为什么?因为人是初始化的,并且在线程中添加了数据,并且线程的开始需要一定时间,但是我们的主函数不会等待数据直接获得数据。结果,尚未初始化人员或未添加数据。出版或初始化的线程安全问题是由错误的时间或地点引起的。
首先,查看由多线程操作同时引起的运行结果错误。
如代码所示,首先定义一个int类型的静态变量i,然后启动两个线程,然后在变量上执行10,000 i ++操作。理论结果应为20,000,但实际结果却少得多。比理论结果。例如,可能是15796或16923。结果每次都不同。为什么?
这是因为在多线程下,线程的执行和调度由CPU确定,并且CPU的调度线程在时间的时间内分配,并且每个线程都可以获得一定的时间胶片。如果线程的时间胶片的耗尽,它将被暂停,并且将CPU资源提供给其他线程,因此可能会出现线程安全问题。对于I ++操作,它看起来像是一系列代码。实际上,这不是原子操作。其执行步骤是三个步骤:
如果线程1首先到达i = 1,然后执行i+1,则结果尚未急于保存。目前,线程1被剪切到线程2执行,线程2的值仍然为i = 1,然后thread 2 execution ecutionution ecutionution i+1,i = 2,结果2为2,线程1结果为2,结果为2,2,结果为2,最终结果是2,不是我们期望i = 3,它具有线程安全问题。
对于这种情况的决定,可以治疗原子类,并且在这里没有讲座。
什么是活动?从字面上看,我们可以将其解释为不成功的线程,也就是说,该过程的最终结果无法运行。与由前两个线程的安全问题引起的数据错误或错误引起的数据错误或错误相比,活动问题的后果可能是严重的,那么哪些问题可以防止线程变得可能发生?摘要是以下三个:
死锁和死锁是最常见的活动问题。死锁互相指的是彼此的资源,但与此同时,他们不放弃,他们想先执行自己,然后等待他们等待,如下所示:
首先,在代码中创建两个对象O1。O2作为同步锁的对象。Polyte 1首先获得O1对象锁定,然后执行逻辑获奖者睡眠1秒钟。如果您想获得O2锁,则线程2想要获得O1锁,但锁定由另一方持有。目前,发生僵局。这总是在等待另一方首先发布资源,因此在没有任何结果的情况下无法停止该过程。
生活锁的第二个活动问题是活锁。活锁与死锁非常相似。也是该程序尚未等待结果。但是,与死锁相比,活锁还活着。这是什么意思?因为线程没有被阻止,它总是在运行,但并非结果。
例如:在消息队列中,通常处理该错误时,当队列的重试机制将在队列头上重新输入以进行优先处理,但是无论执行了多少次消息,无法正确执行正确执行。最及时的位置数量最大的是导致线程,但是该程序从未得到结果。这是活锁的问题。
饥饿的第三个典型问题是饥饿。饥饿意味着当需要某些资源,尤其是CPU资源时,该线程不可用。如果执行CPU不会导致线程在没有运行并引起问题的情况下运行。
例如:使用线程池时,如果集核线程的数量太小,则执行线程时,您会遇到由大文件读取的IO阻塞,或将数据库插入到死锁中或HTTP请求中网络阻塞和超时时间是此超时。几个范围的情况将导致其他线程无法执行资源并饿了很长时间。
以上是一些线程安全问题。我们需要考虑这些发展。这些场景在高发和发型中尤为常见。它还可以考虑访谈中的许多其他要点。
原始:https://juejin.cn/post/7111138985631547422