线程安全:当多个线程访问某一个类(对象或方法时),这个类始终都能实现出正确的行为。那么这个类就是线程安全的。
package com.hbsi.thread;
/***
* 并发编程基础
* @author jia
*
*/
public class MyThread extends Thread{
int sum = 5;
@Override
public void run(){
sum--;
System.out.println(Thread.currentThread().getName()+" sum的值是:"+sum);
}
public static void main(String[] args) {
Thread thread = new MyThread();
Thread t1 = new Thread(thread,"t1");
Thread t2 = new Thread(thread,"t2");
Thread t3 = new Thread(thread,"t3");
Thread t4 = new Thread(thread,"t4");
Thread t5 = new Thread(thread,"t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
以上代码执行的结果是:
t2 sum的值是:3
t3 sum的值是:1
t4 sum的值是:2
t1 sum的值是:3
t5 sum的值是:0
可以看到,线程的执行并不会按照我们所规定的程序顺序流程执行。因此sum的值不是从5-0之间变化的。由此,就出现了当多个线程对同一个对象进行数据修改时,就会出现数据不一致的现象。
出现此种情况,通常我们使用synchronized加锁控制。
代码修改如下,
package com.hbsi.thread;
/***
* 并发编程基础
* @author jia
*
*/
public class MyThread extends Thread{
int sum = 5;
@Override
public synchronized void run(){
sum--;
System.out.println(Thread.currentThread().getName()+" sum的值是:"+sum);
}
public static void main(String[] args) {
Thread thread = new MyThread();
Thread t1 = new Thread(thread,"t1");
Thread t2 = new Thread(thread,"t2");
Thread t3 = new Thread(thread,"t3");
Thread t4 = new Thread(thread,"t4");
Thread t5 = new Thread(thread,"t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
只是在run方法上进行了加锁控制。
执行结果:
t1 sum的值是:4
t5 sum的值是:3
t4 sum的值是:2
t3 sum的值是:1
t2 sum的值是:0
现在可以看到,执行的结果是递减的,但是线程并不是按照之前代码顺序结构进行执行的。
这一块,我们可以理解一下,当多个线程访问MyThread的run方法时,以排队的方式进行处理(这里的排队是按照cpu分配的顺序而定的,相当于抢占cpu的执行权),一个线程想要执行synchroized修饰的方法里的代码。首先应该先获取锁。如果拿到锁就执行synchroized代码里的内容,拿不到锁这个线程就不断的尝试这把锁,直到拿到为止。多个线程获取同一把锁,就会出锁竞争的问题。