在实际生产过程中,多线程的线程安全性是非常复杂的,如果没有进行充足的同步操作,多线程中的操作执行顺序是难以预测的。
举例来说,我们有一个序列号生成器,在单线程中它可以正常的工作,但是在多线程环境中则会导致数据错乱,如下代码所示非线程安全的序列生成器:
public class SequenceGenerator {
/**
*工具类一般都使构造方法私有化。保证安全性。
**/
private SequenceGenerator(){}
private static int sequence;
/** 获取序列号 */
public static int getSequence() {
// 这里返回sequence++ 那么会先返回sequence,再执行++操作
return sequence++;
}
}
在本例中,对获取sequence值有三步操作,先从内存中读取sequence的值,再返回sequence的值,然后对sequence进行自增操作。在这个过程中,如果两个线程执行的时机不对,那么就有可能同时读取到相同的sequence值,此时引发线程问题。
我们将上述类改造成线程安全的类:
public class SequenceGenerator {
/**
*工具类一般都使构造方法私有化。保证安全性。
**/
private SequenceGenerator(){}
private static int sequence;
/** 获取序列号 */
public synchronized static int getSequence() {
// 这里返回sequence++ 那么会先返回sequence,再执行++操作
return sequence++;
}
}
很简单,只需要加上synchronized关键字即可完成线程的同步,不过synchronized的效率并不是很好,在高并发的情况下,就不够用了。本篇主要记录多线程中的各种概念,其他部分暂时不提。
在多线程中,可能会发生活跃性问题,按照《Java Concurrency in Practice》所述,活跃性问题可以归结为“某件正确的事情最终会发生”。即当某个通向正确结果的过程或者操作无法继续执行时,活跃性问题就会发生。在串行程序中(单线程),活跃性问题可以表现为死循环。在多线程中,将会是另一种形式:死锁。
多线程能够很大程度上提升性能,但是线程在运行调度时总是会有很大的开销,在线程同步时,也将占用很多的开销。
对于更多的内容,将会后续更新。
网友评论