多线程同步中的门道(一)
在涉及到多线程的开发时,线程同步的考虑是不可缺少的,否则很可能会造成各种超出预料的错误结果。以自己的学习经历来说,对于刚开始接触线程同步的人可能会感觉非常简单,在多线程操作可能会造成数据混乱的地方同步一下不就行了嘛,加个synchronized关键字,多简单!可是随着开发的深入,会渐渐的发现仅仅是一个synchronized关键字也不是那么简单,里面的门道和考虑到的情况还是不少。本系列就着循序渐进的程序和大家探讨一下synchronized关键字使用中的各种情形和会造成的各种意料之外和意料之中的结果,欢迎各位大神轻拍。
synchronized涉及到同步方法、同步代码块、同步类、同步对象、静态方法等,本系列来挨个探讨。
注:因为考虑到文章篇幅和为了突出我们要分析的关键代码,所以下面程序有可能不会是最优写法。
未作线程同步
我们先来看看,在多线程运行下,未作线程同步的程序。
[测试程序1]
/**
* Test case 1.
* There is no thread synchronization.
*/
public class Test {
public static void main(String[] args) {
final TestCase test = new TestCase();
Thread thread1 = new Thread() {
@Override
public void run() {
test.function();
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
test.function();
}
};
thread1.start();
thread2.start();
}
}
class TestCase {
public void function() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread()。getName() + " executed result: " + i);
}
}
}
上面的测试程序很简单,定义了一个测试用例类,类中有一个循环输出5次"线程名+输出次数"的方法。然后设置了两个线程,启动这两个线程跑这个测试用例对象的方法,查看会有什么样的输出结果。后面的测试程序基本都是在此程序上修改变化而出,用来测试不同情况。
运行程序,某次运行的结果可能如下:
Thread-0 executed result: 0
Thread-1 executed result: 0
Thread-1 executed result: 1
Thread-0 executed result: 1
Thread-1 executed result: 2
Thread-1 executed result: 3
Thread-1 executed result: 4
Thread-0 executed result: 2
Thread-0 executed result: 3
Thread-0 executed result: 4
从程序输出结果可以看出,Thread-0和Thread-1是无规则交叉输出的,也就意味着在未作线程同步的情况下,两个线程同时执行着TestCase的function方法,这种是属于线程不安全的。
同步方法
我们对上面的程序进行一下修改,加一个synchronized关键字用来同步方法。
[测试程序2.1]
/**
* Test case 2.1. synchronized method.
*/
public class Test {
public static void main(String[] args) {
final TestCase test = new TestCase();
Thread thread1 = new Thread() {
@Override
public void run() {
test.function();
}
};