关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象时是可以再次得到该对象的锁的。这也证明在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。
// class Service
public class Service {
synchronized public void service1() {
System.out.println("service1");
service2();
}
synchronized public void service2() {
System.out.println("service2");
service3();
}
synchronized public void service3() {
System.out.println("service3");
service4();
}
synchronized public void service4() {
System.out.println("service4");
}
}
// class Thread06
public class Thread06 extends Thread{
@Override
public void run() {
super.run();
Service service = new Service();
service.service1();
}
}
// main class
public static void main(String[] args) {
service();
}
private static void service() {
Thread06 thread = new Thread06();
thread.start();
}
输出如下:
service1
service2
service3
service4
“可重入锁”的概念是:自己可以再次获取自己的内部锁。比如有1条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。
可重入锁也支持父子类继承的环境中。
// class Sup
public class Sup {
public int i = 10;
synchronized public void operateSupMethod() {
try{
i --;
System.out.println("sup print i=" + i);
Thread.sleep(100);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
// class Sub
public class Sub extends Sup{
synchronized public void operateSubMethod() {
try{
while(i > 0) {
i --;
System.out.println("sub print i=" + i);
Thread.sleep(100);
this.operateSupMethod();
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
// class Thread07
public class Thread07 extends Thread{
@Override
public void run() {
super.run();
Sub sub = new Sub();
sub.operateSubMethod();
}
}
// main class
public static void main(String[] args) {
sub();
}
private static void sub() {
Thread07 thread = new Thread07();
thread.start();
}
输出结果:
sub print i=9
sup print i=8
sub print i=7
sup print i=6
sub print i=5
sup print i=4
sub print i=3
sup print i=2
sub print i=1
sup print i=0
从以上结果可以看到,当存在父子类继承关系时,子类是完全可以通过“可重入锁”调用父类的同步方法的。
当一个线程执行的代码异常时,其所持有的锁会自动释放。
// class Object01
public class Object01 {
synchronized public void testMethod() {
if("a".equals(Thread.currentThread().getName())) {
System.out.println("ThreadName=" + Thread.currentThread().getName()
+ " run beginTime=" + System.currentTimeMillis());
int i = 1;
while(i == 1) {
if(("" + Math.random()).substring(0, 8).equals("0.123456")) {
System.out.println("ThreadName=" + Thread.currentThread().getName()
+ " run exceptionTime=" + System.currentTimeMillis());
Integer.parseInt("a");
}
}
} else {
System.out.println("Thread B run Time=" + System.currentTimeMillis());
}
}
}
// class ThreadC
public class ThreadC extends Thread{
private Object01 object;
public ThreadC(Object01 object) {
this.object = object;
}
@Override
public void run() {
super.run();
object.testMethod();
}
}
// class ThreadD
public class ThreadD extends Thread{
private Object01 object;
public ThreadD(Object01 object) {
this.object = object;
}
@Override
public void run() {
super.run();
object.testMethod();
}
}
// main class
public static void main(String[] args) {
object01();
}
private static void object01() {
try{
Object01 object = new Object01();
ThreadC tc = new ThreadC(object);
tc.setName("a");
tc.start();
Thread.sleep(500);
ThreadD td = new ThreadD(object);
td.setName("b");
td.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
输出结果:
ThreadName=a run beginTime=1496548324461
ThreadName=a run exceptionTime=1496548324664
Exception in thread "a" java.lang.NumberFormatException: For input string: "a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at com.qbian.thread.Object01.testMethod(Object01.java:14)
at com.qbian.thread.ThreadC.run(ThreadC.java:13)
Thread B run Time=1496548324965
可以看到,在线程名为a执行时出现异常后,会立马将其持有的object 对象的锁释放掉,线程名为b的会立马获得object 对象的锁,继续执行b自身的任务。
同步不具有继承性
即父类的某个方法被synchronized修饰,但子类重写了父类的该方法后没有使用synchronized关键字修饰该方法。当多线程调用子类的该方法时是非同步调用的。要想使子类的该方法也具有同步性就需要在子类重写后的该方法前再次加上synchronized关键字修饰。