线程安全:当多个线程访问某一个类(对象或方法时),这个类始终都能实现出正确的行为。那么这个类就是线程安全的。

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代码里的内容,拿不到锁这个线程就不断的尝试这把锁,直到拿到为止。多个线程获取同一把锁,就会出锁竞争的问题。