背景:对于一个资源类,涉及了两个方法,如下:
class phone{
public synchronized void sendMail(){
System.out.println("发邮件~");
}
public synchronized void call(){
System.out.println("打电话~");
}
}
使用两个线程操纵资源类:
public static void main(String[] args) {
phone phone = new phone();
new Thread(()->{
phone.sendMail();
},"A").start();
}
new Thread(()->{phone.call();},"B").start();
}
第一种情况:两个线程操纵资源类中的两个方法,执行结果:发邮件~
打电话~
第二种情况,在第一个方法上加上延时:
public static void main(String[] args) {
phone phone = new phone();
new Thread(()->{
phone.sendMail();
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
new Thread(()->{phone.call();},"B").start();
}
class phone{
public synchronized void sendMail(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发邮件~");
}
public synchronized void call(){
System.out.println("打电话~");
}
}
结果输出:
发邮件~
打电话~
分析以上两种情况:
两个方法都被synchronized关键字修饰,被修饰的方法的锁是当前方法的调用者;由于main方法中只有一个对象phone,所以在调用两个方法时使用的是同一把锁,一次只能执行该对象的一个方法,谁先拿到锁谁先执行,跟是否sleep无关,因为sleep并不释放锁。
第三种情况,在phone类中再增加一个普通方法,非 ynchronized;
在main方法中调用phone.hello,最终的执行结果为:
hello
发邮件~
- 原因在于hello未使用synchronized关键字修饰,是普通方法,不受锁的影响。
第四种情况:对于两个对象phone1,phone2,分别调用两个方法phone1.sendmail(),phone2.sendmail()—》
phone phone1 = new phone();
phone phone2 = new phone();
new Thread(()->{phone2.call();},"B").start();
new Thread(()->{phone1.sendMail();},"A").start();
执行的顺序为:
打电话~
Disconnected from the target VM, address: '127.0.0.1:11629', transport: 'socket'
发邮件~
原因在于,phone1和phone2是两个对象,两把锁,互不影响,由于sendMail方法sleep了4秒,因此call方法先执行;
第五种情况:在两个方法上加static关键字,一个phone对象
public static synchronized void sendMail(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发邮件~");
}
public static synchronized void call(){
System.out.println("打电话~");
}
执行结果:
打电话~
发邮件~
原因:synchronized关键字加在静态方法上,当前锁对象是Class对象,该对象全局唯一,因此两个方法使用的是同一把锁,由于sendMail方法有延迟因此后执行;
第六种情况:加上普通方法hello(),两个对象
执行结果为:
hello!
发邮件~
打电话~
分析:hello方法总是最先执行,因为不需要锁;call()方法和sendMail()方法执行情况同五,因为不论是几个对象,锁的仍然是Class对象,因此执行顺序是谁先获得锁谁先执行;
第七种情况:一个修饰静态方法,一个修饰实例方法,一个对象;
phone3 p3 = new phone3();
new Thread(()->{p3.hello();},"C").start();
new Thread(()->{p3.sendMail();},"A").start();
new Thread(()->{p3.call();},"B").start();
执行结果
hello!
打电话~
发邮件~
分析:两个方法是两把锁,call()方法不需要等待sendMail()的锁;
第八种情况:一个修饰静态方法,一个修饰实例方法,两个对象;
结果:
hello!
打电话~
发邮件~
原因:两个方法是不同的锁,与对象的个数无关;