《Java并发编程实战》一书中,它是这么描述的:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在调用代码中不需要任何额外的同步或者协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。
简单的说,线程安全是指程序在并发环境运行时,多线程之间能够正确的处理共享变量,程序总是表现出正确完成的行为。注意关键词:并发环境、多线程、共享变量、正确完成。这里所谓的正确完成,就是要保证并发的三大特性:原子性、可见性、有序性。
下面举一个例子:
单线程情况下:
public class OneThreadDemo {
public static void main(String[] args) {
int i = 0;
for (int j = 0; j < 20000; j++) {
i++;
}
System.out.println("最终结果: " + i);
}
}
最终执行结果始终为20000
多线程不考虑线程安全情况下:
public class ManyThreadDemo {
private static int i = 0;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Incrementer());
Thread thread2 = new Thread(new Incrementer());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("最终结果: " + i);
}
private static class Incrementer implements Runnable {
@Override
public void run() {
for (int j = 0; j < 10000; j++) {
i++;
}
}
}
}
最终的结果就不确定了:
image.png
多线程考虑线程安全情况下:
public class ManyThreadSecureDemo {
private static int i = 0;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Incrementer());
Thread thread2 = new Thread(new Incrementer());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("最终结果: " + i);
}
private static class Incrementer implements Runnable {
@Override
public void run() {
for (int j = 0; j < 1000; j++) {
synchronized (ManyThreadSecureDemo.class) {
i++;
}
}
}
}
}
最终执行的结果始终为:2000
image.png
从上面的代码示例不难得出:在多线程环境中,多个线程在同一时刻对同一份资源进行写操作时,在加锁的时候结果符合预期,这就是线程安全的,但没有加锁的时候不符合预期的结果这就是非线程安全的。
其实说白就是:单个线程下程序的运行结果和多线程下程序运行的结果始终保持一致,这就是线程安全的。
网友评论