我们先来看一段代码:
import java.util.ArrayList;
public class MyThreadTest {
private ArrayList<String> list = new ArrayList<String>();
private byte[] lock = new byte[0];
private void addData() {
list.clear();
for (int n = 0; n < 50; n++) {
list.add(String.valueOf(n));
}
System.out.println(list.size());
}
public static void main(String[] args) {
final MyThreadTest mtt = new MyThreadTest();
new Thread(new Runnable() {
@Override
public void run() {
mtt.addData();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
mtt.addData();
}
}).start();
}
}
输出结果:50、50
在看一段代码:
import java.util.ArrayList;
public class MyThreadTest {
private ArrayList<String> list = new ArrayList<String>();
private byte[] lock = new byte[0];
private void addData() {
list.clear();
for (int n = 0; n < 5000; n++) {
list.add(String.valueOf(n));
}
System.out.println(list.size());
}
public static void main(String[] args) {
final MyThreadTest mtt = new MyThreadTest();
new Thread(new Runnable() {
@Override
public void run() {
mtt.addData();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
mtt.addData();
}
}).start();
}
}
输出结果:8828、8971(随机的)
两份代码有什么区别?只不过是把方法中的循环次数改大了而已,但是显然第二次运行结果就不对了,为什么?
这样就引入了线程同步的概念,第一份代码自身不正确,但是运行结果为什么是正确的呢?因为循环次数过少,线程很快就执行完,所以看上去结果是“正确的”。
当我们把这样的程序引入到银行系统中我们猜猜会发生什么?O(∩_∩)O~
在进一步阐述之前,我们需要明确几点:
A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
B.每个对象只有一个锁(lock)与之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
我们看看改如何修改这个程序:
import java.util.ArrayList;
public class MyThreadTest {
private ArrayList<String> list = new ArrayList<String>();
private byte[] lock = new byte[0];
synchronized private void addData() {
list.clear();
for (int n = 0; n < 5000; n++) {
list.add(String.valueOf(n));
}
System.out.println(list.size());
}
public static void main(String[] args) {
final MyThreadTest mtt = new MyThreadTest();
new Thread(new Runnable() {
@Override
public void run() {
mtt.addData();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
mtt.addData();
}
}).start();
}
}
当我们让addData()方法加上同步锁了之后,一次只能有一个线程访问addData()对象,其余线程出于等待状态,输出结果为:5000、5000