zoukankan      html  css  js  c++  java
  • java多线程基本概述(三)——同步块

    1.1、synchronized方法的弊端

    package commonutils;
    
    public class CommonUtils {
    
        public static long beginTime1;
        public static long endTime1;
    
        public static long beginTime2;
        public static long endTime2;
    }
    
    =============================
    package mytask;
    
    import commonutils.CommonUtils;
    
    public class Task {
    
        private String getData1;
        private String getData2;
    
        public synchronized 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 (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    =======================================
    package mythread;
    
    import commonutils.CommonUtils;
    
    import mytask.Task;
    
    public 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();
        }
    
    }
    =============================================
    package mythread;
    
    import commonutils.CommonUtils;
    
    import mytask.Task;
    
    public class MyThread2 extends Thread {
    
        private Task task;
    
        public MyThread2(Task task) {
            super();
            this.task = task;
        }
    
        @Override
        public void run() {
            super.run();
            CommonUtils.beginTime2 = System.currentTimeMillis();
            task.doLongTimeTask();
            CommonUtils.endTime2 = System.currentTimeMillis();
        }
    
    }
    package test;
    
    import mytask.Task;
    import mythread.MyThread1;
    import mythread.MyThread2;
    
    import commonutils.CommonUtils;
    
    public class Run {
    
        public static void main(String[] args) {
            Task task = new Task();
    
            MyThread1 thread1 = new MyThread1(task);
            thread1.start();
    
            MyThread2 thread2 = new MyThread2(task);
            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));
        }
    }

    输出结果:

    begin task
    长时间处理任务后从远程返回的值1 threadName=Thread-0
    长时间处理任务后从远程返回的值2 threadName=Thread-0
    end task
    begin task
    长时间处理任务后从远程返回的值1 threadName=Thread-1
    长时间处理任务后从远程返回的值2 threadName=Thread-1
    end task
    耗时:6

    当把同步方法改为同步代码块时,

    package mytask;
    
    import commonutils.CommonUtils;
    
    public class Task {
    
        private String getData1;
        private String getData2;
    
        public  void doLongTimeTask() {
            synchronized(Task.class){
                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 (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            
        }
    }

    输出结果:

    begin task
    长时间处理任务后从远程返回的值1 threadName=Thread-0
    长时间处理任务后从远程返回的值2 threadName=Thread-0
    end task
    begin task
    长时间处理任务后从远程返回的值1 threadName=Thread-1
    长时间处理任务后从远程返回的值2 threadName=Thread-1
    end task
    耗时:6

    可见,并没有提升效率,这是因为锁定的范围比较广,所以效果和锁方法的差别并不是太。那么可以缩小边界区,也就是资源真正开始竞争的地方。因为类中的成员变量才是资源的竞争对象,所以需要在访问这些变量的地方进行锁定。那么代码改为如下:

    package mytask;
    
    import commonutils.CommonUtils;
    
    public class Task {
    
        private String getData1;
        private String getData2;
    
        public  void doLongTimeTask() {
            
                try {
                    System.out.println("begin task");
                    Thread.sleep(3000);
                    getData1 = "长时间处理任务后从远程返回的值1 threadName="
                            + Thread.currentThread().getName();
                    getData2 = "长时间处理任务后从远程返回的值2 threadName="
                            + Thread.currentThread().getName();
                    synchronized(Task.class){
                        System.out.println(getData1);
                        System.out.println(getData2);
                    }
                    System.out.println("end task");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }    
        }
    }

    输出结果:

    begin task
    begin task
    长时间处理任务后从远程返回的值1 threadName=Thread-0
    长时间处理任务后从远程返回的值2 threadName=Thread-0
    end task
    长时间处理任务后从远程返回的值1 threadName=Thread-1
    长时间处理任务后从远程返回的值2 threadName=Thread-1
    end task
    耗时:3

    这时候可以看到时间已经减小了,这就出现一部分同步,一部分异步了。如何验证是真的一半同步一半异步呢?

    package mytask;
    
    public class Task {
    
        public void doLongTimeTask() {
            for (int i = 0; i < 100; i++) {
                System.out.println("nosynchronized threadName="
                        + Thread.currentThread().getName() + " i=" + (i + 1));
            }
            System.out.println("");
            synchronized (this) {
                for (int i = 0; i < 100; i++) {
                    System.out.println("synchronized threadName="
                            + Thread.currentThread().getName() + " i=" + (i + 1));
                }
            }
    
        }
    }

    输出结果:

    =================================非同步块异步执行
    nosynchronized threadName=Thread-0 i=1
    nosynchronized threadName=Thread-1 i=1
    nosynchronized threadName=Thread-0 i=2
    nosynchronized threadName=Thread-1 i=2
    nosynchronized threadName=Thread-0 i=3
    nosynchronized threadName=Thread-1 i=3
    nosynchronized threadName=Thread-0 i=4
    nosynchronized threadName=Thread-1 i=4
    nosynchronized threadName=Thread-0 i=5
    nosynchronized threadName=Thread-1 i=5
    nosynchronized threadName=Thread-0 i=6
    nosynchronized threadName=Thread-1 i=6
    nosynchronized threadName=Thread-0 i=7
    nosynchronized threadName=Thread-1 i=7
    nosynchronized threadName=Thread-0 i=8
    nosynchronized threadName=Thread-1 i=8
    =================================同步块同步执行
    synchronized threadName=Thread-1 i=85
    synchronized threadName=Thread-1 i=86
    synchronized threadName=Thread-1 i=87
    synchronized threadName=Thread-1 i=88
    synchronized threadName=Thread-1 i=89
    synchronized threadName=Thread-1 i=90
    synchronized threadName=Thread-1 i=91
    synchronized threadName=Thread-1 i=92
    synchronized threadName=Thread-1 i=93
    synchronized threadName=Thread-1 i=94
    synchronized threadName=Thread-1 i=95
    synchronized threadName=Thread-1 i=96
    synchronized threadName=Thread-1 i=97
    synchronized threadName=Thread-1 i=98
    synchronized threadName=Thread-1 i=99
    synchronized threadName=Thread-1 i=100
    synchronized threadName=Thread-0 i=1
    synchronized threadName=Thread-0 i=2
    synchronized threadName=Thread-0 i=3
    synchronized threadName=Thread-0 i=4
    synchronized threadName=Thread-0 i=5
    synchronized threadName=Thread-0 i=6
    synchronized threadName=Thread-0 i=7
    synchronized threadName=Thread-0 i=8
    synchronized threadName=Thread-0 i=9
    synchronized threadName=Thread-0 i=10
    synchronized threadName=Thread-0 i=11
    synchronized threadName=Thread-0 i=12
    synchronized threadName=Thread-0 i=13
    synchronized threadName=Thread-0 i=14
    synchronized threadName=Thread-0 i=15
    synchronized threadName=Thread-0 i=16
  • 相关阅读:
    FPGA之verilog流水灯小程序
    FPGA之Verilog点灯小程序
    FPGA学习入门
    机试题 (用 hash 实现部门管理系统 只记得大概的内容,简洁版) -- 上一篇的优化
    机试题 (用 hash 实现部门管理系统 只记得大概的内容,简洁版) --> 这里改成文件管理系统
    双向循环链表 (只需要一个 head 节点), 从头尾部 删除 插入 数据都比较方便
    使用 head + tail 两个头尾节点实现双向链表 (队列太多会占用内存), 数据的添加删除比较方便
    线程学习
    堆排序演示 ( 这个 堆排函数将适合所有的堆排, 只需要改一下比较函数)
    windows10 下访问 virtualbox 虚拟机的linux15.10/16.04 系统 及 用 putty 访问虚拟机的配置
  • 原文地址:https://www.cnblogs.com/soar-hu/p/6723829.html
Copyright © 2011-2022 走看看