《Java 多线程编程核心技术》笔记——第2章 对象及变量的并发访问(三)

声明:

本博客是本人在学习《Java 多线程编程核心技术》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。

本博客已标明出处,如有侵权请告知,马上删除。

2.2 synchronized 同步语句块

2.2.9 静态同步 synchronized 方法与 synchronized(class) 代码块

关键字 synchronized 还可以应用在 static 静态方法上,如果这样写,那是对当前的 * .java 文件对应的 Class 类进行持锁

下面通过一个示例来演示 synchronized 应用在 static 静态方法上:

  1. 创建一个公共类

    public class Service5 {
        synchronized public static void printA() {
            try {
                System.out.println("printA begin" + " run threadName = " + Thread.currentThread().getName());
                Thread.sleep(3000);
                System.out.println("printA end" + " run threadName = " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        synchronized public static void printB() {
            System.out.println("printB begin" + " run threadName = " + Thread.currentThread().getName());
            System.out.println("printB end" + " run threadName = " + Thread.currentThread().getName());
        }
    }
    
    
  2. 创建两个自定义的线程类

    public class MyThread12 extends Thread {
        @Override
        public void run() {
            super.run();
            Service5.printA();
        }
    }
    
    
    public class MyThread12_2 extends Thread {
        @Override
        public void run() {
            super.run();
            Service5.printB();
        }
    }
    
    
  3. 测试类

    public class MyThread12_Test {
        public static void main(String[] args) {
            MyThread12 myThread12 = new MyThread12();
            myThread12.setName("A");
            myThread12.start();
            MyThread12_2 myThread12_2 = new MyThread12_2();
            myThread12_2.setName("B");
            myThread12_2.start();
        }
    }
    
    

    运行结果

    printA begin run threadName = A
    printA end run threadName = A
    printB begin run threadName = B
    printB end run threadName = B
    
    

分析:从运行结果来看,并没有什么特别之处,都是同步的效果,和将 synchronized 关键字加到非 static 方法上使用的效果是一样的。其实还是有本质上的不同的,synchronized 关键字加到 static 静态方法上是给 Class 类上锁,而 synchronized 关键字加到非 static 静态方法上是给对象上锁

为了验证它们不是一个锁,下面通过一个示例来演示:

  1. 创建一个公共类

    public class Service6 {
        synchronized public static void printA() {
            try {
                System.out.println("printA begin" + " run threadName = " + Thread.currentThread().getName());
                Thread.sleep(3000);
                System.out.println("printA end" + " run threadName = " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        synchronized public static void printB() {
            System.out.println("printB begin" + " run threadName = " + Thread.currentThread().getName());
            System.out.println("printB end" + " run threadName = " + Thread.currentThread().getName());
        }
    
        synchronized public void printC() {
            System.out.println("printC begin" + " run threadName = " + Thread.currentThread().getName());
            System.out.println("printC end" + " run threadName = " + Thread.currentThread().getName());
    
        }
    }
    
    
  2. 创建三个自定义的线程类

    public class MyThread13 extends Thread {
        private Service6 service6;
    
        public MyThread13(Service6 service6) {
            this.service6 = service6;
        }
    
        @Override
        public void run() {
            super.run();
            service6.printA();
        }
    }
    
    
    public class MyThread13_2 extends Thread {
        private Service6 service6;
    
        public MyThread13_2(Service6 service6) {
            this.service6 = service6;
        }
    
        @Override
        public void run() {
            super.run();
            service6.printB();
        }
    }
    
    
    public class MyThread13_3 extends Thread {
        private Service6 service6;
    
        public MyThread13_3(Service6 service6) {
            this.service6 = service6;
        }
    
        @Override
        public void run() {
            super.run();
            service6.printC();
        }
    }
    
    
  3. 测试类

    public class MyThread13Test {
        public static void main(String[] args) {
            Service6 service6 = new Service6();
            MyThread13 myThread13 = new MyThread13(service6);
            myThread13.setName("A");
            myThread13.start();
            MyThread13_2 myThread13_2 = new MyThread13_2(service6);
            myThread13_2.setName("B");
            myThread13_2.start();
            MyThread13_3 myThread13_3 = new MyThread13_3(service6);
            myThread13_3.setName("C");
            myThread13_3.start();
        }
    }
    
    

    运行结果

    printA begin run threadName = A
    printC begin run threadName = C
    printC end run threadName = C
    printA end run threadName = A
    printB begin run threadName = B
    printB end run threadName = B
    

分析:方法 printC 为异步运行,异步的原因是持有不同的锁,PrintC 方法持有的是对象锁,printA 和 printB 方法持有的是 Class 锁

Class 锁可以对类的所有对象实例起作用,下面通过一个示例来演示:

  1. 创建一个公共类

    public class Service7 {
        synchronized public static void printA() {
            try {
                System.out.println("printA begin" + " run threadName = " + Thread.currentThread().getName());
                Thread.sleep(3000);
                System.out.println("printA end" + " run threadName = " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        synchronized public static void printB() {
            System.out.println("printB begin" + " run threadName = " + Thread.currentThread().getName());
            System.out.println("printB end" + " run threadName = " + Thread.currentThread().getName());
        }
    }
    
    
  2. 创建两个自定义的线程类

    public class MyThread14 extends Thread {
        private Service7 service7;
    
        public MyThread14(Service7 service7) {
            this.service7 = service7;
        }
    
        @Override
        public void run() {
            super.run();
            service7.printA();
        }
    }
    
    
    public class MyThread14_2 extends Thread {
        private Service7 service7;
    
        public MyThread14_2(Service7 service7) {
            this.service7 = service7;
        }
    
        @Override
        public void run() {
            super.run();
            service7.printB();
        }
    }
    
    
  3. 测试类

    public class MyThread14Test {
        public static void main(String[] args) {
            Service7 service7 = new Service7();
            Service7 service7_2 = new Service7();
            MyThread14 myThread14 = new MyThread14(service7);
            myThread14.setName("A");
            myThread14.start();
            MyThread14_2 myThread14_2 = new MyThread14_2(service7_2);
            myThread14_2.setName("B");
            myThread14_2.start();
        }
    }
    
    

    运行结果

    printA begin run threadName = A
    printA end run threadName = A
    printB begin run threadName = B
    printB end run threadName = B
    

同步 synchronized(class) 代码块的作用其实和 synchronized static 方法的作用一样,也是对 class 类上锁

下面通过一个示例演示:

  1. 创建一个公共类

    public class Service8 {
        public static void printA() {
            synchronized (Service8.class) {
                try {
                    System.out.println("printA begin" + " run threadName = " + Thread.currentThread().getName());
                    Thread.sleep(3000);
                    System.out.println("printA end" + " run threadName = " + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void printB() {
            synchronized (Service8.class) {
                System.out.println("printB begin" + " run threadName = " + Thread.currentThread().getName());
                System.out.println("printB end" + " run threadName = " + Thread.currentThread().getName());
            }
        }
    }
    
    
  2. 创建两个自定义的线程类

    public class MyThread15 extends Thread {
        private Service8 service8;
    
        public MyThread15(Service8 service8) {
            this.service8 = service8;
        }
    
        @Override
        public void run() {
            super.run();
            service8.printA();
        }
    }
    
    
    public class MyThread15_2 extends Thread {
        private Service8 service8;
    
        public MyThread15_2(Service8 service8) {
            this.service8 = service8;
        }
    
        @Override
        public void run() {
            super.run();
            service8.printB();
        }
    }
    
    
  3. 测试类

    public class MyThread15Test {
        public static void main(String[] args) {
            Service8 service8 = new Service8();
            Service8 service8_2 = new Service8();
            MyThread15 myThread15 = new MyThread15(service8);
            myThread15.setName("A");
            myThread15.start();
            MyThread15_2 myThread15_2 = new MyThread15_2(service8_2);
            myThread15_2.setName("B");
            myThread15_2.start();
        }
    }
    
    

    运行结果

    printA begin run threadName = A
    printA end run threadName = A
    printB begin run threadName = B
    printB end run threadName = B
    

2.2.10 数据类型 String 的常量池特性

在 JVM 中具有 String 常量池缓存的功能,下面通过一个示例来演示:

public class Test {
    public static void main(String[] args) {
        String a = "a";
        String b = "a";
        System.out.println(a == b);
    }
}

将 synchronized(string) 同步块与 String 联合使用时,要注意常量池带来的一些例外,下面通过一个示例来演示:

  1. 创建一个公共类

    public class Service9 {
        public void print(String stringParam) {
            try {
                synchronized (stringParam) {
                    while (true) {
                        System.out.println(Thread.currentThread().getName());
                        Thread.sleep(1000);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    
  2. 创建两个自定义的线程类

    public class MyThread16 extends Thread {
        private Service9 service9;
    
        public MyThread16(Service9 service9) {
            this.service9 = service9;
        }
    
        @Override
        public void run() {
            super.run();
            service9.print("A");
        }
    }
    
    
    public class MyThread16_2 extends Thread {
        private Service9 service9;
    
        public MyThread16_2(Service9 service9) {
            this.service9 = service9;
        }
    
        @Override
        public void run() {
            super.run();
            service9.print("A");
        }
    }
    
    
  3. 测试类

    public class MyThread16Test {
        public static void main(String[] args) {
            Service9 service9 = new Service9();
            MyThread16 myThread16 = new MyThread16(service9);
            myThread16.setName("A");
            myThread16.start();
            MyThread16 myThread16_2 = new MyThread16(service9);
            myThread16_2.setName("B");
            myThread16_2.start();
        }
    }
    
    

    运行结果

    A
    A
    A
    A
    A
    A
    A
    A
    ...
    

分析:出现这样的情况就是因为 String 的两个值都是 A,两个线程持有相同的锁,所以造成线程 B 不能执行。这就是 String 常量池所带来的问题。因此在大多数情况下,同步 synchronized 代码块都不使用 String 作为锁对象,而改用其他,比如 new Object() 实例化一个 Object 对象,但它并不放入缓存中

下面通过一个示例来演示:

  1. 创建一个公共类

    public class Service10 {
        public void print(Object object) {
            try {
                synchronized (object) {
                    while (true) {
                        System.out.println(Thread.currentThread().getName());
                        Thread.sleep(1000);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    
  2. 创建两个自定义的线程类

    public class MyThread17 extends Thread {
        private Service10 service10;
    
        public MyThread17(Service10 service10) {
            this.service10 = service10;
        }
    
        @Override
        public void run() {
            super.run();
            service10.print(new Object());
        }
    }
    
    
    public class MyThread17_2 extends Thread {
        private Service10 service10;
    
        public MyThread17_2(Service10 service10) {
            this.service10 = service10;
        }
    
        @Override
        public void run() {
            super.run();
            service10.print(new Object());
        }
    }
    
    
  3. 测试类

    public class MyThread17Test {
        public static void main(String[] args) {
            Service10 service10 = new Service10();
            MyThread17 myThread17 = new MyThread17(service10);
            myThread17.setName("A");
            myThread17.start();
            MyThread17_2 myThread17_2 = new MyThread17_2(service10);
            myThread17_2.setName("B");
            myThread17_2.start();
        }
    }
    
    

    运行结果

    A
    B
    B
    A
    B
    A
    B
    A
    B
    A
    B
    A
    ...
    

分析:交替打印的原因是持有的锁不是同一个

2.2.11 同步 synchronized 方法无限等待与解决

同步方法容易造成死循环,下面通过一个示例来演示:

  1. 创建一个公共类

    public class Service11 {
        synchronized public void methodA() {
            System.out.println("methodA begin");
            boolean isContinue = true;
            while (isContinue) {
            }
            System.out.println("methodA end");
        }
    
        synchronized public void methodB() {
            System.out.println("methodB begin");
            System.out.println("methodB end");
        }
    }
    
    
  2. 创建两个自定义的线程类

    public class MyThread18 extends Thread {
        private Service11 service11;
    
        public MyThread18(Service11 service11) {
            this.service11 = service11;
        }
    
        @Override
        public void run() {
            super.run();
            service11.methodA();
        }
    }
    
    
    public class MyThread18_2 extends Thread {
        private Service11 service11;
    
        public MyThread18_2(Service11 service11) {
            this.service11 = service11;
        }
    
        @Override
        public void run() {
            super.run();
            service11.methodB();
        }
    }
    
    
  3. 测试类

    public class MyThread18Test {
        public static void main(String[] args) {
            Service11 service11 = new Service11();
            MyThread18 myThread18 = new MyThread18(service11);
            myThread18.start();
            MyThread18_2 myThread18_2 = new MyThread18_2(service11);
            myThread18_2.start();
        }
    }
    
    

    运行结果

    methodA begin
    

分析:线程 B 永远得不到运行机会,锁死了

这时就可以使用同步块来解决这样的问题了,下面通过一个示例来演示:

  1. 更改 Service11

    public class Service11 {
        private Object object1 = new Object();
        private Object object2 = new Object();
    
        public void methodA() {
            synchronized (object1) {
                System.out.println("methodA begin");
                boolean isContinue = true;
                while (isContinue) {
                }
                System.out.println("methodA end");
            }
        }
    
        public void methodB() {
            synchronized (object2) {
                System.out.println("methodB begin");
                System.out.println("methodB end");
            }
        }
    }
    
    
  2. 再次运行,运行结果如下

    methodA begin
    methodB begin
    methodB end
    

2.2.12 多线程的死锁

Java 线程死锁是一个经典的多线程问题,因为不同的线程都在等待不可能被释放的锁,从而导致所有任务都无法继续完成。在多线程技术中,“死锁” 是必须避免的,因为这会造成线程的 “假死”。

下面通过一个示例来演示多线程的死锁:

  1. 创建一个自定义的线程类

    public class DealThread implements Runnable {
        public String username;
        public Object lock1 = new Object();
        public Object lock2 = new Object();
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        @Override
        public void run() {
            if (username == "A") {
                synchronized (lock1) {
                    try {
                        System.out.println("username = " + username);
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock2) {
                        System.out.println("执行顺序为:lock1 -> lock2");
                    }
                }
            }
            if (username == "B") {
                synchronized (lock2) {
                    try {
                        System.out.println("username = " + username);
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock1) {
                        System.out.println("执行顺序为:lock2 -> lock1");
                    }
                }
            }
        }
    }
    
    
  2. 测试类

    public class DealThreadTest {
        public static void main(String[] args) {
            try {
                DealThread dealThread = new DealThread();
                dealThread.setUsername("A");
                Thread thread = new Thread(dealThread);
                thread.start();
                Thread.sleep(100);
                dealThread.setUsername("B");
                Thread thread_2 = new Thread(dealThread);
                thread_2.start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    

    运行结果

    username = A
    username = B
    

分析:死锁是程序设计的 Bug,在设计程序时就要避免双方互相持有对方锁的情况。需要说明的是,本实验使用 synchronized 嵌套的代码结构来实现死锁,其实不使用嵌套的 synchronized 代码结构也会出现死锁,与嵌套不嵌套无任何关系,不要被代码结构所误导。只要互相等待对方释放锁就有可能出现死锁

2.3.13 内置类与静态内置类

先来看一下简单的内置类测试

  1. 创建 PublicClass 类,其中包含内置类 PrivateClass

    public class PublicClass {
        private String username;
        private String password;
    
        class PrivateClass {
            private String age;
            private String address;
    
            public String getAge() {
                return age;
            }
    
            public void setAge(String age) {
                this.age = age;
            }
    
            public String getAddress() {
                return address;
            }
    
            public void setAddress(String address) {
                this.address = address;
            }
    
            public void printPublicProperty() {
                System.out.println(username + " " + password);
            }
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    
    
  2. 测试类

    public class PublicClassTest {
        public static void main(String[] args) {
            PublicClass publicClass = new PublicClass();
            publicClass.setUsername("usernameValue");
            publicClass.setPassword("passwordValue");
            System.out.println(publicClass.getUsername() + " " + publicClass.getPassword());
            PublicClass.PrivateClass privateClass = publicClass.new PrivateClass();
            privateClass.setAge("ageValue");
            privateClass.setAddress("addressValue");
            System.out.println(privateClass.getAge() + " " + privateClass.getAddress());
        }
    }
    

    运行结果

    usernameValue passwordValue
    ageValue addressValue
    

内置类还有一种叫做静态内置类

  1. 创建 PublicClass 类,其中包含静态内置类 PrivateClass

    public class PublicClass2 {
        static private String username;
        static private String password;
    
        static class PrivateClass {
            private String age;
            private String address;
    
            public String getAge() {
                return age;
            }
    
            public void setAge(String age) {
                this.age = age;
            }
    
            public String getAddress() {
                return address;
            }
    
            public void setAddress(String address) {
                this.address = address;
            }
    
            public void printPublicProperty() {
                System.out.println(username + " " + password);
            }
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    
  2. 测试类

    public class PublicClass2Test {
        public static void main(String[] args) {
            PublicClass2 publicClass2 = new PublicClass2();
            publicClass2.setUsername("usernameValue");
            publicClass2.setPassword("passwordValue");
            System.out.println(publicClass2.getUsername() + " " + publicClass2.getPassword());
            PublicClass2.PrivateClass privateClass = new PublicClass2.PrivateClass();
            privateClass.setAge("ageValue");
            privateClass.setAddress("addressValue");
            System.out.println(privateClass.getAge() + " " + privateClass.getAddress());
        }
    }
    

    运行结果

    usernameValue passwordValue
    ageValue addressValue
    

2.2.14 内置类与同步:实验1

本实验测试的案例是在内置类中有两个同步方法。但使用的是不同的锁,打印的结果也是异步的

  1. 创建 OutClass 类,其中包含静态内置类 InnerClass

    public class OutClass {
        static class InnerClass {
            public void method1() {
                synchronized ("其他的锁") {
                    for (int i = 1; i <= 10; i++) {
                        System.out.println(Thread.currentThread().getName() + " i=" + i);
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            public synchronized void method2() {
                for (int i = 11; i <= 20; i++) {
                    System.out.println(Thread.currentThread().getName() + " i=" + i);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    
  2. 测试类

    public class OutClassTest {
        public static void main(String[] args) {
            final OutClass.InnerClass innerClass = new OutClass.InnerClass();
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    innerClass.method1();
                }
            }, "A");
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    innerClass.method2();
                }
            }, "B");
            thread1.start();
            thread2.start();
        }
    }
    

    运行结果

    B i=11
    A i=1
    B i=12
    A i=2
    A i=3
    B i=13
    A i=4
    B i=14
    A i=5
    B i=15
    A i=6
    B i=16
    A i=7
    B i=17
    B i=18
    A i=8
    A i=9
    B i=19
    B i=20
    A i=10
    

注意:由于持有不同的"对象监视器",所以打印的结果也是异步的。

2.2.15 内置类与同步:实验2

本实验测试同步代码块 synchronized(class2) 对 innerclass2 上锁后,其他线程只能以同步的方式调用 innerclass2 中的静态同步方法。

  1. 创建 OutClass2 类,其中包含静态内置类 InnerClass1 和 InnerClass2

    public class OutClass2 {
        static class InnerClass1 {
            public void method1(Innerclass2 innerclass2) {
                String threadName = Thread.currentThread().getName();
                synchronized (innerclass2) {
                    System.out.println(threadName + " 进入 InnerClass1 类中的 method1 方法");
                    for (int i = 0; i < 10; i++) {
                        System.out.println("i=" + i);
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(threadName + " 离开 InnerClass1 类中的 method1 方法");
                }
            }
            public synchronized void method2() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName + " 进入 InnerClass1 类中的 method2 方法");
                for (int j = 0; j < 10; j++) {
                    System.out.println("j=" + j);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(threadName + " 离开 InnerClass1 类中的 method2 方法");
            }
        }
    
        static class Innerclass2 {
            public synchronized void method1() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName + " 进入 InnerClass2 类中的 method1 方法");
                for (int k = 0; k < 10; k++) {
                    System.out.println("k=" + k);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(threadName + " 离开 InnerClass2 类中的 method1 方法");
            }
        }
    }
    
  2. 测试类

    public class OutClass2Test {
        public static void main(String[] args) {
            final OutClass2.InnerClass1 innerClass1 = new OutClass2.InnerClass1();
            final OutClass2.Innerclass2 innerclass2 = new OutClass2.Innerclass2();
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    innerClass1.method1(innerclass2);
                }
            }, "A");
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    innerClass1.method2();
                }
            }, "B");
            Thread thread3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    innerclass2.method1();
                }
            }, "C");
            thread1.start();
            thread2.start();
            thread3.start();
        }
    }
    

    运行结果

    A 进入 InnerClass1 类中的 method1 方法
    B 进入 InnerClass1 类中的 method2 方法
    i=0
    j=0
    i=1
    j=1
    j=2
    i=2
    j=3
    i=3
    j=4
    i=4
    j=5
    i=5
    j=6
    i=6
    j=7
    i=7
    j=8
    i=8
    i=9
    j=9
    A 离开 InnerClass1 类中的 method1 方法
    B 离开 InnerClass1 类中的 method2 方法
    C 进入 InnerClass2 类中的 method1 方法
    k=0
    k=1
    k=2
    k=3
    k=4
    k=5
    k=6
    k=7
    k=8
    k=9
    C 离开 InnerClass2 类中的 method1 方法
    

2.2.16 锁对象的改变

在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程之间就是异步的

  1. 创建一个公共类

    public class Service12 {
        private String lock = "123";
    
        public void testMethod() {
            try {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + " begin " + System.currentTimeMillis());
                    lock = "456";
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName() + " end " + System.currentTimeMillis());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
  2. 创建两个自定义的线程类

    public class MyThread19 extends Thread{
        private Service12 service12;
    
        public MyThread19(Service12 service12) {
            this.service12 = service12;
        }
    
        @Override
        public void run() {
            super.run();
            service12.testMethod();
        }
    }
    
    public class MyThread19_2 extends Thread{
        private Service12 service12;
    
        public MyThread19_2(Service12 service12) {
            this.service12 = service12;
        }
    
        @Override
        public void run() {
            super.run();
            service12.testMethod();
        }
    }
    
  3. 测试类

    public class MyThread19Test {
        public static void main(String[] args) throws InterruptedException {
            Service12 service12 = new Service12();
            MyThread19 myThread19 = new MyThread19(service12);
            myThread19.setName("A");
            MyThread19_2 myThread19_2 = new MyThread19_2(service12);
            myThread19_2.setName("B");
            myThread19.start();
            Thread.sleep(500);
            myThread19_2.start();
        }
    }
    

    运行结果

    A begin 1583841197512
    B begin 1583841198012
    A end 1583841199513
    B end 1583841200013
    

分析:可以看到 A、B 之间是异步的,这是因为 500 毫秒后,线程 B 取得的锁是 “456”

继续实验,注释测试类中的 Thread.sleep(500)

public class MyThread19Test {
    public static void main(String[] args) throws InterruptedException {
        Service12 service12 = new Service12();
        MyThread19 myThread19 = new MyThread19(service12);
        myThread19.setName("A");
        MyThread19_2 myThread19_2 = new MyThread19_2(service12);
        myThread19_2.setName("B");
        myThread19.start();
//        Thread.sleep(500);
        myThread19_2.start();
    }
}

运行结果

A begin 1583841999930
A end 1583842001930
B begin 1583842001930
B end 1583842003931

分析:线程 A 和 B 持有的锁都是 “123”,虽然将锁改成了 “456”,但结果还是同步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bm1998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值