public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.senMesg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
public synchronized void senMesg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
这两个问题涉及同一个对象的同步方法之间的互相调用。当线程执行一个对象的同步方法时,它就持有了这个对象的锁。当它需要再次调用这个对象的另一个同步方法时,如果这个方法也是同步的,那么这个线程就可以直接进入该方法,而无需重新获取锁。这就是“可重入锁”的体现。
public class Test2 {
public static void main(String[] args) {
Phone1 phone = new Phone1();
new Thread(()->{
phone.senMesg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.hello();
},"B").start();
}
}
class Phone1{
public synchronized void senMesg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
public void hello(){
System.out.println("hello");
}
}
这个问题涉及父子类继承关系中使用同步方法。父类中的同步方法在被子类继承后,子类同样可以使用这个同步方法,并且可以在这个同步方法中调用父类的同步方法,这也是“可重入锁”的体现。
public class Test3 {
public static void main(String[] args) {
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
new Thread(()->{
phone1.senMesg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone2{
public synchronized void senMesg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
这个问题涉及不同对象的同步方法之间的互相调用。当线程执行一个对象的同步方法时,它就持有了这个对象的锁。如果它需要调用另一个对象的同步方法,那么这个线程就需要获取另一个对象的锁才能进入该方法,因此这两个同步方法之间没有“可重入锁”的关系。
public class Test4 {
public static void main(String[] args) {
Phone3 phone1 = new Phone3();
new Thread(()->{
phone1.senMesg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone1.call();
},"B").start();
}
}
class Phone3{
public static synchronized void senMesg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
这两个问题涉及静态同步方法和非静态同步方法之间的互相调用。静态同步方法持有的是类锁,而非静态同步方法持有的是对象锁,因此它们持有的锁是不同的,没有“可重入锁”的关系。
public class Test5 {
public static void main(String[] args) {
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
new Thread(()->{
phone1.senMesg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone4{
public static synchronized void senMesg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
当synchronized
关键字用于方法或代码块时,它可以用来实现对象级别的锁和类级别的锁。
对象级别锁:
synchronized
用于非静态方法时,锁对象是调用该方法的实例对象。即每个对象实例都有自己的锁。synchronized
用于代码块时,锁对象可以是任意的Java对象。通常情况下,我们使用某个共享资源作为锁对象。类级别锁:
synchronized
用于静态方法时,锁对象是当前方法所属的类对象(Class
对象)。总结:
synchronized
关键字通过获取锁来保证同一时间只有一个线程可以执行同步代码块或方法。