• 《Java多线程编程核心技术》读后感(五)


    下面验证上面三条结论

    验证第一条结论:

    package Second;
    
    public class MyObject {
    }
    package Second;
    
    public class Service {
    
        public void testMethod1(MyObject object) {
            synchronized (object) {
                try {
                    System.out.println("testMethod1 ____getLock time="
                            + System.currentTimeMillis() + " run ThreadName="
                            + Thread.currentThread().getName());
                    Thread.sleep(2000);
                    System.out.println("testMethod1 releaseLock time="
                            + System.currentTimeMillis() + " run ThreadName="
                            + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    package Second;
    
    public class ThreadA extends Thread {
    
        private Service service;
        private MyObject object;
    
        public ThreadA(Service service, MyObject object) {
            super();
            this.service = service;
            this.object = object;
        }
    
        @Override
        public void run() {
            super.run();
            service.testMethod1(object);
        }
    
    }
    package Second;
    
    public class ThreadB extends Thread {
        private Service service;
        private MyObject object;
    
        public ThreadB(Service service, MyObject object) {
            super();
            this.service = service;
            this.object = object;
        }
    
        @Override
        public void run() {
            super.run();
            service.testMethod1(object);
        }
    
    }
    package Second;
    
    public class Run1_1 {
    
        public static void main(String[] args) {
            Service service = new Service();
            MyObject object = new MyObject();
    
            ThreadA a = new ThreadA(service, object);
            a.setName("a");
            a.start();
    
            ThreadB b = new ThreadB(service, object);
            b.setName("b");
            b.start();
        }
    
    }

    同步的原因是使用了同一个“对象监视器“”。如果使用不同的“”对象监视器“”会出现什么效果呢?见下面

    package Second;
    
    public class Run1_2 {
    
        public static void main(String[] args) {
            Service service = new Service();
            MyObject object1 = new MyObject();
            MyObject object2 = new MyObject();
    
            ThreadA a = new ThreadA(service, object1);
            a.setName("a");
            a.start();
    
            ThreadB b = new ThreadB(service, object2);
            b.setName("b");
            b.start();
        }
    
    }
    package Second;
    
    public class Run1_2 {
    
        public static void main(String[] args) {
            Service service = new Service();
            MyObject object1 = new MyObject();
            MyObject object2 = new MyObject();
    
            ThreadA a = new ThreadA(service, object1);
            a.setName("a");
            a.start();
    
            ThreadB b = new ThreadB(service, object2);
            b.setName("b");
            b.start();
        }
    
    }

    验证第2个结论

    package Second;
    
    public class MyObject {
        synchronized public void speedPrintString() {
            System.out.println("speedPrintString ____getLock time="
                    + System.currentTimeMillis() + " run ThreadName="
                    + Thread.currentThread().getName());
            System.out.println("-----------------");
            System.out.println("speedPrintString releaseLock time="
                    + System.currentTimeMillis() + " run ThreadName="
                    + Thread.currentThread().getName());
        }
    }
    package Second;
    
    public class Service {
    
        public void testMethod1(MyObject object) {
            synchronized (object) {
                try {
                    System.out.println("testMethod1 ____getLock time="
                            + System.currentTimeMillis() + " run ThreadName="
                            + Thread.currentThread().getName());
                    Thread.sleep(5000);
                    System.out.println("testMethod1 releaseLock time="
                            + System.currentTimeMillis() + " run ThreadName="
                            + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    package Second;
    
    public class ThreadA extends Thread {
    
        private Service service;
        private MyObject object;
    
        public ThreadA(Service service, MyObject object) {
            super();
            this.service = service;
            this.object = object;
        }
    
        @Override
        public void run() {
            super.run();
            service.testMethod1(object);
        }
    
    }
    package Second;
    
    public class ThreadB extends Thread {
        private MyObject object;
    
        public ThreadB(MyObject object) {
            super();
            this.object = object;
        }
    
        @Override
        public void run() {
            super.run();
            object.speedPrintString();
        }
    }
    package Second;
    
    public class Run {
    
        public static void main(String[] args) throws InterruptedException {
            Service service = new Service();
            MyObject object = new MyObject();
    
            ThreadA a = new ThreadA(service, object);
            a.setName("a");
            a.start();
    
            Thread.sleep(100);
    
            ThreadB b = new ThreadB(object);
            b.setName("b");
            b.start();
        }
    
    }

    验证第3个结论

    其他代码与第二个实验相同

    package Second;
    
    public class MyObject {
        public void speedPrintString() {
            synchronized (this) {
                System.out.println("speedPrintString ____getLock time="
                        + System.currentTimeMillis() + " run ThreadName="
                        + Thread.currentThread().getName());
                System.out.println("-----------------");
                System.out.println("speedPrintString releaseLock time="
                        + System.currentTimeMillis() + " run ThreadName="
                        + Thread.currentThread().getName());
            }
        }
    }

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

    是对当前的*.java文件对应的class类进行持锁

    package Second;
    
    public class Service {
    
        synchronized public static void printA() {
            try {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printA");
                Thread.sleep(3000);
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printA");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        synchronized public static void printB() {
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "进入printB");
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "离开printB");
        }
    
    }
    package Second;
    
    public class ThreadA extends Thread {
        @Override
        public void run() {
            Service.printA();
        }
    
    }
    package Second;
    
    public class ThreadB extends Thread {
        @Override
        public void run() {
            Service.printB();
        }
    }
    package Second;
    
    public class Run {
    
        public static void main(String[] args) {
    
            ThreadA a = new ThreadA();
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB();
            b.setName("B");
            b.start();
    
        }
    
    }

    下面展示synchronized关键字加到非static静态方法上的锁

    package Second;
    
    public class Service {
    
        synchronized public static void printA() {
            try {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printA");
                Thread.sleep(3000);
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printA");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        synchronized public static void printB() {
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "进入printB");
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "离开printB");
        }
    
        synchronized public void printC() {
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "进入printC");
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "离开printC");
        }
    
    }
    package Second;
    
    public class ThreadA extends Thread {
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.printA();
        }
    
    }
    package Second;
    
    public class ThreadB extends Thread {
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.printB();
        }
    }
    package Second;
    
    public class ThreadC extends Thread {
    
        private Service service;
    
        public ThreadC(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.printC();
        }
    }

    异步的原因是持有不同的锁,一个是对象锁,另外一个是class锁,而class锁可以对类的所有对象实例起作用,下面验证

    package Second;
    
    public class Service {
    
        synchronized public static void printA() {
            try {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printA");
                Thread.sleep(3000);
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printA");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        synchronized public static void printB() {
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "进入printB");
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "离开printB");
        }
    
    }
    package Second;
    
    public class ThreadA extends Thread {
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.printA();
        }
    }
    package Second;
    
    public class ThreadB extends Thread {
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.printB();
        }
    }
    package Second;
    
    public class Run {
    
        public static void main(String[] args) {
    
            Service service1 = new Service();
            Service service2 = new Service();
    
            ThreadA a = new ThreadA(service1);
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB(service2);
            b.setName("B");
            b.start();
    
        }
    
    }

    同步synchronized(class)代码块的作用其实和synchronized static方法的作用是一样的。下面测试

    package Second;
    
    public class Service {
    
        public static void printA() {
            synchronized (Service.class) {
                try {
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "进入printA");
                    Thread.sleep(3000);
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "离开printA");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        public static void printB() {
            synchronized (Service.class) {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printB");
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printB");
            }
        }
    }
    package Second;
    
    public class ThreadA extends Thread {
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.printA();
        }
    }
    package Second;
    
    public class ThreadB extends Thread {
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.printB();
        }
    }
    package Second;
    
    public class Run {
    
        public static void main(String[] args) {
    
            Service service1 = new Service();
            Service service2 = new Service();
    
            ThreadA a = new ThreadA(service1);
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB(service2);
            b.setName("B");
            b.start();
    
        }
    
    }

     数据类型String的常量池特性

    package Second;
    
    public class Service {
        public static void print(String stringParam) {
            try {
                synchronized (stringParam) {
                    while (true) {
                        System.out.println(Thread.currentThread().getName());
                        Thread.sleep(1000);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    package Second;
    
    public class ThreadA extends Thread {
        private Service service;
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.print("AA");
        }
    }
    package Second;
    
    public class ThreadB extends Thread {
        private Service service;
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.print("AA");
        }
    }
    package Second;
    
    public class Run {
    
        public static void main(String[] args) {
    
            Service service = new Service();
    
            ThreadA a = new ThreadA(service);
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB(service);
            b.setName("B");
            b.start();
    
        }
    
    }

    出现这样的情况就是因为String的两个值都是AA,两个线程持有相同的锁,所以造成线程B不能执行。这就是String常量池所带来的问题。

    因此在大多数情况下,同步synchronized代码块都不使用String作为锁对象,而改用其他的,比如new object()实例化一个object对象,但它并不放入缓存中。

    package Second;
    
    public class Service {
        public static void print(Object object) {
            try {
                synchronized (object) {
                    while (true) {
                        System.out.println(Thread.currentThread().getName());
                        Thread.sleep(1000);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    package Second;
    
    public class ThreadA extends Thread {
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.print(new Object());
        }
    }
    package Second;
    
    public class ThreadB extends Thread {
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.print(new Object());
        }
    }
    package Second;
    
    public class Run {
    
        public static void main(String[] args) {
    
            Service service = new Service();
    
            ThreadA a = new ThreadA(service);
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB(service);
            b.setName("B");
            b.start();
    
        }
    
    }

    交替打印是因为持有的锁不是同一个

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

    同步方法容易造成死循环

    package Second;
    
    public class Service {
        synchronized public void methodA() {
            Object object1 = new Object();
    
            System.out.println("methodA begin");
            boolean isContinueRun = true;
            while (isContinueRun) {
            }
            System.out.println("methodA end");
    
        }
    
        synchronized public void methodB() {
            Object object2 = new Object();
    
            System.out.println("methodB begin");
            System.out.println("methodB end");
    
        }
    }
    package Second;
    
    public class ThreadA extends Thread {
    
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.methodA();
        }
    
    }
    package Second;
    
    public class ThreadB extends Thread {
    
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.methodB();
        }
    
    }
    package Second;
    
    public class Run {
    
        public static void main(String[] args) {
            Service service = new Service();
    
            ThreadA athread = new ThreadA(service);
            athread.start();
    
            ThreadB bthread = new ThreadB(service);
            bthread.start();
        }
    
    }

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

    package Second;
    
    public class Service {
        public void methodA() {
            Object object1 = new Object();
            synchronized (object1) {
                System.out.println("methodA begin");
                boolean isContinueRun = true;
                while (isContinueRun) {
                }
                System.out.println("methodA end");
            }
        }
    
        public void methodB() {
            Object object2 = new Object();
            synchronized (object2) {
                System.out.println("methodB begin");
                System.out.println("methodB end");
            }
        }
    }

  • 相关阅读:
    Oracle--SQL Developer创建连接及使用
    MongoDB--使用修改器修改文档
    MongoDB 的创建、查询、更新、删除
    window下 Mongodb无法访问28107的有关问题(转)
    十一、存储过程
    十、视图
    九、增、改、查数据
    七、联结表
    八、组合查询和全文本搜索
    六、聚合函数、数据分组
  • 原文地址:https://www.cnblogs.com/Michael2397/p/7843350.html
Copyright © 2020-2023  润新知