多个线程访问一些程序中的资源时,会发生资源抢占。我们用线程同步来解决这个问题,保证线程安全。
如果有一个全局变量 int sum = 1;有A,B两个线程对sum进行操作,他们获取资源时都是sum = 1,而线程A对其进行+1写回去变成了 2,如果我们希望线程B对其也进行+1操作后sum = 3,但是因为B线程获取到的是sum = 1,所以操作后写回去也是sum = 2 。为了解决类似的问题,引入了锁的概念——即在一个线程操作时进行锁定,暂时不给别的资源操作,直到其释放。
例子:使用synchronized进行同步
先看不加锁的情况:
class Total {
private int sum; //共享资源
public Total() {
this.sum = 0;
}
public int getSum() {
return sum;
}
public void setSum(int sum) {
this.sum = sum;
}
}
class TotalTest implements Runnable {
static final Total total = new Total();
@Override
public void run() {
for(int i = 0;i<1000;i++) {
total.setSum(total.getSum()+1);
}
}
}
public class T_test {
public static void main(String[] args) {
TotalTest tt1 = new TotalTest();
/*
* 开了两个线程进行模拟 ,如果输出的sum结果不等于2000
* 那么就说明出现了线程安全问题
*/
Thread t1 = new Thread(tt1);
Thread t2 = new Thread(tt1);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(tt1.total.getSum());
}
}
输出: 1181
解决方案:在访问共享资源的代码块外加上同步锁
class TotalTest implements Runnable {
static final Total total = new Total();
@Override
public void run() {
for(int i = 0;i<1000;i++) {
synchronized (this) { //加入了实例锁
total.setSum(total.getSum()+1);
}
}
}
}
前面我们只实例化了一个线程实例,加实例锁可以解决线程同步问题。下面我们实例化两个线程对象
public class T_test {
public static void main(String[] args) {
TotalTest tt1 = new TotalTest();
TotalTest tt2 = new TotalTest();
/*
* 开了两个线程进行模拟 ,如果输出的sum结果不等于2000
* 那么就说明出现了线程安全问题
*/
Thread t1 = new Thread(tt1);
Thread t2 = new Thread(tt2);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(tt1.total.getSum());
}
}
这时输出:1970
解决方案 :加上类级锁
public void run() {
for(int i = 0;i<1000;i++) {
synchronized (TotalTest.class) { //加上了TotalTest类级锁
total.setSum(total.getSum()+1);
}
}
}
输出:2000