1、如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出现错误,有三种方式可以修复这个问题:
(1)不在线程之间共享该状态变量
(2)将状态变量修改为不可变的变量
(3)在访问状态变量时使用同步
线程安全性的定义:某个类的行为与其规范完全一致。也可以说,可以在多个线程中调用,并且在线程之间不会出现错误的交互。
无状态对象一定是线程安全的。
下面就是一个线程不安全的例子:
package com.ys.thread;
public class ThreadTest implements Runnable{
private int count = 0;
public void run() {
for(int i=0;i<30;i++){
count++;
System.out.println(Thread.currentThread().getName()+": "+count);
}
}
public static void main(String[] args) {
ThreadTest t = new ThreadTest();
Thread t1 = new Thread(t, "t1");
Thread t2 = new Thread(t, "t2");
// Thread t3 = new Thread(t, "t3");
// Thread t4 = new Thread(t, "t4");
t1.start();
t2.start();
// t3.start();
// t4.start();
}
}
这个例子就会出现线程的问题,使得count值非依次递增。
在并发编程中,这种由于不恰当的执行时序而出现不正确的结果是一种非常重要的情况,它有一个非正式的名字:竞态条件。
造成竞态条件的可能原因就是使用“先检查后执行”的方法,当我们检查时,假设count是3,但当我们执行时,count的状态已经发生变化,已经变为了4或其他的值。
下面引出数据竞争定义:如果在访问共享的非final类型的域时没有采用同步来进行协同,那么就会出现数据竞争。
数据竞争和竞态条件很相似,我也不知道如何区分它们,如果哪位大牛知道,可以在评论中给我讲解一下,在这先感谢了。
原子操作:假定有两种操作A和B,如果从执行A的线程来看,当另一个线程执行B时,要么将B全部执行完,要么完全不执行B,那么A和B对彼此来说就是原子的。
如果将“检查执行”内的线程改为原子操作,就不会出现竞态条件或者数据竞争。