专业的JAVA编程教程与资源

网站首页 > java教程 正文

读完就懂的Java并发编程(java并发编程从入门到精通)

temp10 2024-10-13 09:29:29 java教程 14 ℃ 0 评论

前言

Java天生具有对多线程和并发强大的支持,这使得编写并发应用程序变得非常容易。 但通常情况下,多线程应用程序在调试过程、排除故障的时候都比较困难。 从我的并发应用程序的经验来看,大多数问题都是在大规模运行时发现的。因此,我们在开发的时候一定要了解它的原理,防范于未然。大家肯定对Java并发编程有点望而生畏的感觉。其实不是很难。看完这篇文章你心中应该有一个明白的概念的。我相信。

读完就懂的Java并发编程(java并发编程从入门到精通)

Java并发

我们来看这第一个例子:

public class Foo {

private int x;

public int getX() {

return x;

}

public void setX(int x) {

this.x = x;

}

}

我们问题来了,这个类是线程安全的么?答案显而易见,肯定不是的。而我们要怎么做才能保证它线程是安全的么?大家一定会想到是在get和set方法前面加上synchronized关键词。

synchronized

大家估计或多或少有见过这个关键字,但是具体的玩法估计没有很深刻的了解。

当一个线程调用synchronized方法或代码块时,它会尝试获取一个内部锁(监视器)。一旦线程获得锁定,其他线程将阻塞,直到锁定被释放。

这看起来是挺好的解决方案! 但synchronized有一些缺点:

  • 线程饿死:synchronized并不保证公平。 这意味着如果有很多线程竞争获得锁定,那么有可能一些线程没有机会继续,这意味着进入了闲置状态且完全不会被调用到(我们程之为饿死的状态)。

  • 死锁:从其他同步代码调用同步代码可能导致死锁。

  • 吞吐量较低:使用synchronized意味着只有一个线程在特定的对象上执行。 在很多情况下,这是没有必要的,因为仅在写入时锁定对变量的访问就足够了,如果当前所有线程正在读取(并发读取),则不需要锁定变量。

从上面几点来看,我们就知道synchronized对于线程安全是有利的,但并不是最佳的。如果胡乱的使用synchronized关键字的话会大大的影响程序的运行效率或者运行结果。

Volatile

另一个解决并发的方式就是使用volatile,上面的代码就是在private int x;改成private volatile int x;

volatile能够保证程序的:

  • 可见性:如果一个线程改变了一个变量的值,那么这个改变对于读取该变量的其他线程立即可见。 这是通过不允许编译器或JVM在CPU寄存器中分配这些变量来保证的。 对volatile变量的任何写操作都会立即刷新到主内存中,并且从主内存中读取它。 这意味着会有一些性能损失,但是从并发性的角度来看,这是一个很好的事情。

  • 不允许指令排序:有时为了性能优化,JVM重新排序指令。 访问volatile变量时不允许这样做。 对volatile变量的访问不会通过访问其他volatile变量进行重新排序,也不能访问其他正常字段。 这使得对其周围的非volatile字段的写入立即可见于其他线程。

然而volatile也不是万能药,记住在下面场景中千万不要用volatile:类似于 ++, --, 等。这是因为这些操作会转化成多个读写指令。

在一个多线程程序中,这样的操作应该是原子的,volatile不能保证。 Java SE带有一系列的原子类,如AtomicInteger,AtomicLong和AtomicBoolean,可以用来解决这个问题。

小结

我尽力用比较简单的文字来描述java多线程和并发的问题。希望对大家有所帮助。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表