我们先看看下列代码:
class MyThread extends Thread{
private int count=5;
@Override
public void run() {
super.run();
count--;
System.out.println("由"+this.currentThread().getName()+"计算,count="+count);
}
}
public class Run {
public static void main(String[] args) {
MyThread mythread=new MyThread();
Thread a=new Thread(mythread,"A");
Thread b=new Thread(mythread,"B");
Thread c=new Thread(mythread,"C");
Thread d=new Thread(mythread,"D");
Thread e=new Thread(mythread,"E");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
运行结果为;
由B计算,count=3
由D计算,count=0
由E计算,count=1
由C计算,count=2
由A计算,count=3
我们想得到的打印结果是不重复且依次递减的。
在某些JVM中,i--的操作要分成如下三步;
(1)取得原有i值
(2)计算i-1
(3)对i进行赋值
在这三个步骤中,如果有多个线程同时访问,那么一定会出现非线程安全问题。
现将代码更改如下:
class MyThread extends Thread{
private int count=5;
@Override
synchronized public void run() {
super.run();
count--;
System.out.println("由"+this.currentThread().getName()+"计算,count="+count);
}
}
public class Run {
public static void main(String[] args) {
MyThread mythread=new MyThread();
Thread a=new Thread(mythread,"A");
Thread b=new Thread(mythread,"B");
Thread c=new Thread(mythread,"C");
Thread d=new Thread(mythread,"D");
Thread e=new Thread(mythread,"E");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
输出结果如下:
由A计算,count=4
由D计算,count=3
由C计算,count=2
由B计算,count=1
由E计算,count=0
通过在run方法前加入synchornized关键字,使得多个线程在执行run方法的时候,以排队的方式进行处理。当一个线程调用run前,先判断run方法有没有被上锁,如果上锁,说明有其他线程正在调用run方法,必须等待其他线程对run方法调用结束后才可以执行run方法。这样也就实现了排队调用run方法的目的,也就达到了按顺序对count变量减一的效果。synchornized可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区”或“临界区”。
当一个线程想要执行同步方法里面的代码时,线程首先尝试去拿这把锁,如果能够拿到这把锁,那么这个线程就可以执行synchornied里面的代码,如果不能拿到这把锁,那么这个线程就会不断地尝试拿这把锁,直到能够拿到为止,而且是有多个线程同时去争抢这把锁。