zoukankan      html  css  js  c++  java
  • Java多线程-synchronized同步语句块

    synchronized 声明方法的弊端

    比如A线程调用同步方法执行一个很长时间的任务,那么B线程则必须等待比较长的时间。

    示例:

    public class SyncMethod {
    
        public static void main(String[] args) {
            Task task = new Task();
            MyThread1 thread1 = new MyThread1(task);
            MyThread2 thread2 = new MyThread2(task);
            thread1.start();
            thread2.start();
    
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long beginTime = CommonUtils.beginTime1;
            if (CommonUtils.beginTime2 < CommonUtils.beginTime1) {
                beginTime = CommonUtils.beginTime2;
            }
            long endTime = CommonUtils.endTime1;
            if (CommonUtils.endTime2 > CommonUtils.endTime1) {
                endTime = CommonUtils.endTime2;
            }
            System.out.println("耗时:" + ((endTime - beginTime) / 1000));
        }
    
        static class Task {
            private String getData1;
            private String getData2;
    
            synchronized public void doLongTimeTask() {
                try {
                    System.out.println("begin task");
                    Thread.sleep(3000);
                    getData1 = "长时间处理任务后从远程返回的值 1 threadName = " + Thread.currentThread().getName();
                    getData2 = "长时间处理任务后从远程返回的值 2 threadName = " + Thread.currentThread().getName();
                    System.out.println(getData1);
                    System.out.println(getData2);
                    System.out.println("end task");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        static class CommonUtils {
            public static long beginTime1;
            public static long endTime1;
            public static long beginTime2;
            public static long endTime2;
        }
    
        static class MyThread1 extends Thread {
            private Task task;
    
            public MyThread1(Task task) {
                super();
                this.task = task;
            }
    
            @Override
            public void run() {
                super.run();
                CommonUtils.beginTime1 = System.currentTimeMillis();
                task.doLongTimeTask();
                CommonUtils.endTime1 = System.currentTimeMillis();
            }
        }
    
        static class MyThread2 extends Thread {
            private Task task;
    
            public MyThread2(Task task) {
                this.task = task;
            }
    
            @Override
            public void run() {
                super.run();
                CommonUtils.beginTime2 = System.currentTimeMillis();
                task.doLongTimeTask();
                CommonUtils.endTime2 = System.currentTimeMillis();
            }
        }
    }

    运行结果如图:

    使用 synchronized 块改造成一半异步,一半同步

    示例:

    public class SyncMethod {
    
        public static void main(String[] args) {
            Task task = new Task();
            MyThread1 thread1 = new MyThread1(task);
            MyThread2 thread2 = new MyThread2(task);
            thread1.start();
            thread2.start();
    
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long beginTime = CommonUtils.beginTime1;
            if (CommonUtils.beginTime2 < CommonUtils.beginTime1) {
                beginTime = CommonUtils.beginTime2;
            }
            long endTime = CommonUtils.endTime1;
            if (CommonUtils.endTime2 > CommonUtils.endTime1) {
                endTime = CommonUtils.endTime2;
            }
            System.out.println("耗时:" + ((endTime - beginTime) / 1000));
        }
    
        static class Task {
            private String getData1;
            private String getData2;
    
            public void doLongTimeTask() {
                try {
                    System.out.println("begin task");
                    Thread.sleep(3000);
                    synchronized (this) {
                        getData1 = "长时间处理任务后从远程返回的值 1 threadName = " + Thread.currentThread().getName();
                        getData2 = "长时间处理任务后从远程返回的值 2 threadName = " + Thread.currentThread().getName();
                        System.out.println(getData1);
                        System.out.println(getData2);
                    }
    
                    System.out.println("end task");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        static class CommonUtils {
            public static long beginTime1;
            public static long endTime1;
            public static long beginTime2;
            public static long endTime2;
        }
    
        static class MyThread1 extends Thread {
            private Task task;
    
            public MyThread1(Task task) {
                super();
                this.task = task;
            }
    
            @Override
            public void run() {
                super.run();
                CommonUtils.beginTime1 = System.currentTimeMillis();
                task.doLongTimeTask();
                CommonUtils.endTime1 = System.currentTimeMillis();
            }
        }
    
        static class MyThread2 extends Thread {
            private Task task;
    
            public MyThread2(Task task) {
                this.task = task;
            }
    
            @Override
            public void run() {
                super.run();
                CommonUtils.beginTime2 = System.currentTimeMillis();
                task.doLongTimeTask();
                CommonUtils.endTime2 = System.currentTimeMillis();
            }
        }
    }

    运行结果如图:

    synchronized 代码块间的同步性

    在使用同步 synchronized(this) 代码块时需要注意的是,当一个线程访问 object 的一个 synchronized(this) 同步代码块时,其他线程对同一个 object 中的所有其他 synchronized(this) 同步代码块的访问将被阻塞(言外之意是,非同步代码块,还是能被异步访问),

    所以 synchronized 锁定的是当前对象

    示例:

    public class SyncBlock {
        public static void main(String[] args) {
            ObjectService service = new ObjectService();
            ThreadA threadA = new ThreadA(service);
            ThreadB threadB = new ThreadB(service);
            threadA.setName("a");
            threadB.setName("b");
            threadA.start();
            threadB.start();
        }
    
        static class ObjectService {
            public void serviceMethodA() {
                try {
                    synchronized (this) {
                        System.out.println("A begin time = " + System.currentTimeMillis());
                        Thread.sleep(2000);
                        System.out.println("A end time = " + System.currentTimeMillis());
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            public void serviceMethodB() {
                System.out.println("B begin time = " + System.currentTimeMillis());
                System.out.println("B end time = " + System.currentTimeMillis());
            }
        }
    
        static class ThreadA extends Thread {
            private ObjectService service;
    
            public ThreadA(ObjectService service) {
                this.service = service;
            }
    
            @Override
            public void run() {
                super.run();
                service.serviceMethodA();
            }
        }
    
        static class ThreadB extends Thread {
            private ObjectService service;
    
            public ThreadB(ObjectService service) {
                this.service = service;
            }
    
            @Override
            public void run() {
                super.run();
                service.serviceMethodB();
            }
        }
    }

    运行结果如图:

  • 相关阅读:
    FBWF和EWF的对比
    还原数据库备份文件时,关于“System.Data.SqlClient.SqlError:媒体集有2个媒体簇,但只提供了1个。必须提供所有成员”的处理方式
    C#基础(八)——C#数据类型的转换
    C#基础(七)——静态类与非静态类、静态成员的区别
    C#基础(六)——值类型与引用类型
    C#基础(五)——类中私有构造函数作用
    C#基础(四)——ref与out的区别
    C#基础(三)—重载与覆盖
    oracle exists和 not exists 的用法
    easyUI 常见问题点
  • 原文地址:https://www.cnblogs.com/lkc9/p/12483293.html
Copyright © 2011-2022 走看看