线程安全概念:当多个线程访问某个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类就是线程安全的。
synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区” 或“临界区”
示例:
public class MyThread extends Thread {
private int count = 5 ;
@Override
public void run() {
count -- ;
System.out.println(this.currentThread().getName() + ": count is " + count);
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread, "t1");
Thread t2 = new Thread(myThread, "t2");
Thread t3 = new Thread(myThread, "t3");
Thread t4 = new Thread(myThread, "t4");
Thread t5 = new Thread(myThread, "t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}}
如上代码,方法上我们并没有加锁。同时运行5个线程,期望count能够按照我们预期的依次递减。但是结果如下
其中并没有按照我们预期中的进行递减,这是因为当多个线程访问MyThread的run方法时,是以CPU分配的先后顺序进行的,并不是按照代码的先后顺序。所以很有可能当某段代码还没执行完,CPU就把这个资源分配给其他线程了,导致共享变量的错乱。
因此,做出如下修改:
public class MyThread extends Thread {
private int count = 5 ;
@Override
public synchronized void run() {
count -- ;
System.out.println(this.currentThread().getName() + ": count is " + count);
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread, "t1");
Thread t2 = new Thread(myThread, "t2");
Thread t3 = new Thread(myThread, "t3");
Thread t4 = new Thread(myThread, "t4");
Thread t5 = new Thread(myThread, "t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}}
在run方法上加上synchronize,使其成为一段互斥的代码。当线程尝试执行synchronize修的代码时,会先去尝试获取锁,拿到锁则执行代码。拿不到则会不断的尝试获取这把锁,直到拿到为止,而且是多个线程同时去竞争这把锁(比如1000个线程,只有一个线程能拿到锁,其他999个线程去竞争,对我们CPU的压力就比较大了,应该尽量避免)