首页 > 编程知识 正文

java编程思想(java多线程应用场景)

时间:2023-05-06 09:23:08 阅读:95419 作者:3196

前言

我们在过去的传统编程过程中,为了在将数据放入内存时只考虑单一线程访问,定义了内存中的数据类型。 所以,不需要太多考虑。 因为很安全。

但是,如果数据同时由多个线程操作,则会出现问题。 为了确保可见性和准确性,必须同步对多个线程的数据的访问。

ps:在JMM模型中进行多线程同时操作时,由父线程共享的资源变量存储在父线程的存储器空间中,作为子线程有各自的线程空间,因此也称为工作线程的存储器空间,按每个操作共享资源的代码该过程可能会增加每个线程可读的共享变量的值,并且由于在父线程空间中的变量值被更新时,一个子线程对共享数据的更改不会立即出现在其他子线程中,因此操作的可见性存在问题。

例如,定义常规计数器数据类型Counter类。

虽然该类在单线程环境中没有问题,但是如果多个线程访问同一个计数器实例,它将完全无法工作。 由于并发操作的每个线程都将副本复制到其自己的线程空间中进行操作,因此完成后更新共享的变量可能会导致数据不一致。

同步锁操作实现

此时,可以通过使用同步关键字或使用volatile关键字进行同步来解决问题。

这个同步的类经常解决多个线程同时访问的问题。 但是,我们知道,同步关键字背后的实现原理是对修饰的方法进行锁定处理,而且这个锁定和解锁过程不是轻量级的机制,都有很多缺点。

如果多个线程尝试获取相同的锁定,则大多数线程将挂起,并在解除锁定时重置。 如果我们的操作极限区域很小,这个开销就会很大。 特别是在经常获取锁定,存在很多冲突的情况下。 另一个缺点是,在其他线程正在等待解除锁定时什么也做不了。 如果具有当前锁定的线程的执行出现延迟,则其他线程可能会由于页面错误、量子时钟结束等原因而无法长时间执行。

原子操作实现原理

为了避免这些问题,Java推出了解锁算法。 该算法没有使用锁定机制,提高了可伸缩性和性能。

它利用了下位机械指令的原子性,确保了上位操作的原子性。 简单来说,就是将上位级的操作分解为与下位级的原子操作级对应的操作,使各操作不会被中断或被盗。

我们知道,在处理资源冲突时,一般有两种思路。

一种是悲观的模式,相信纷争一定会发生,事先制定好防止对策。 其中上锁的就是这种悲观模式的实现。 另一个是乐观的模型,按照每次操作都有成功也有失败的可能性的想法进行处理。 成功则已执行,失败则再试一次。 悲观的模式是,总之锁定资源使用的是阻塞思维,原子操作不采用锁定机制,是大家可以访问的非阻塞思维。

目前,实际的处理器大多提供了一些指令,它们大大简化了这种无阻塞算法的实现,其中目前使用最多的操作是比较和交换操作(CAS )。

该算法的工作原理是,3个参数分别工作的存储器地址,是预计当前工作的数值,需要成为新的值。

首先,检查指定的内存地址值是否与当前的预期值相同,如果相同,则更新为新值,如果与预期值不同,则中止此次操作,在此次操作完成后返回指定的内存地址值。 因此,如果多个线程要执行CAS操作,则一个线程获胜,其他线程什么也不做。 调用方可以选择重试或执行其他操作。

实际上,我们平时经常使用这种比较和设定的操作原理来实现其他功能操作。 方法的原理与CAS完全相同,但返回一个布尔值,指示操作是否成功。

可用的原子操作类型

Java5.0之前,开发人员不能直接使用该操作,但是在Java 5.0中添加了几个原子变量(int、long、boolean、参照变量)。

int版和long版也支持数字操作。 JVM使用硬件计算机、CAS或锁定的Java实现编译了这些类,使其成为更好的操作方法。

所有atomicintegeratomiclongatomicbooleanatomicreference都通过compareAndSet ()等方法支持CAS操作,因此支持多线程访问而不是同步操作

/p26.toutiaoimg.com/origin/pgc-image/321cf5685dca4c20b032d61d0357efbb?from=pc">

这里incrementAndGet()和decrementAndGet()方法是AtomicLong和AtomicInteger类提供的两个数值操作。

另外还有getAndDecrement(), getAndIncrement(), getAndAdd(int i) 和 addAndGet()等可以调用的安全操作。

这个版本比同步版本更快,而且线程安全。

最后,我们只使用compareAndSet()方法实现了一个遵循CAS模式的increment()方法。

这看起来有些复杂,但这就是实现非阻塞算法的代价。其思想就是当检测到冲突时,我们会重试,直到操作成功。

这是非阻塞算法的通用模式,我们在非阻塞流NIO操作中会经常看到这种模式的使用。

自定义复杂原子操作类型

下面我们举一个实例来实现一个Stack类:

图 2-1

图 2-2

它确实比在这两个方法上使用synchronized要复杂,但是如果存在争用,它的性能也会更好,即使没有争用的情况下,它的性能通常也是不错的。

总之,原子变量类是实现非阻塞算法的一种很好的方法,而且也是volatile变量的一个很好的替代方法,因为它们可以提供原子性和可见性。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。