zoukankan      html  css  js  c++  java
  • synchronized同步语句块

    用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长时间。在这样的情况下可以使用synchronized同步语句块来解决。

    1、synchronized方法的弊端

    为了证明synchronized关键字声明方法是有弊端的,看下图示例

    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 commonutils;
    
    public class CommonUtils {
    
        public static long beginTime1;
        public static long endTime1;
    
        public static long beginTime2;
        public static long endTime2;
    }
    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

    2、synchronized同步代码块的使用

    当两个并发线程访问同一个对象ibject中的synchronized(this)同步代码块时,一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块后才能执行该代码块。

    package service;
    
    public class ObjectService {
    
        public void serviceMethod() {
            try {
                synchronized (this) {
                    System.out.println("begin time=" + System.currentTimeMillis());
                    Thread.sleep(2000);
                    System.out.println("end    end=" + System.currentTimeMillis());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    package extthread;
    
    import service.ObjectService;
    
    public class ThreadA extends Thread {
    
        private ObjectService service;
    
        public ThreadA(ObjectService service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            super.run();
            service.serviceMethod();
        }
    
    }
    package extthread;
    
    import service.ObjectService;
    
    public class ThreadB extends Thread {
        private ObjectService service;
    
        public ThreadB(ObjectService service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            super.run();
            service.serviceMethod();
        }
    }
    package test.run;
    
    import service.ObjectService;
    import extthread.ThreadA;
    import extthread.ThreadB;
    
    public class Run {
    
        public static void main(String[] args) {
            ObjectService service = new ObjectService();
    
            ThreadA a = new ThreadA(service);
            a.setName("a");
            a.start();
    
            ThreadB b = new ThreadB(service);
            b.setName("b");
            b.start();
        }
    
    }
    结果:
    begin time =1403579513572
    end    end  1403579515572
    begin time = 1403579515572
    end   end =1403579517572

    这里虽然使用了synchronized同步代码块,但执行的效率还是没有提高

    package mytask;
    
    public class Task {
    
        private String getData1;
        private String getData2;
    
        public void doLongTimeTask() {
            try {
                System.out.println("begin task");
                Thread.sleep(3000);
    
                String privateGetData1 = "长时间处理任务后从远程返回的值 1 threadName="
                        + Thread.currentThread().getName();
                String privateGetData2 = "长时间处理任务后从远程返回的值2 threadName="
                        + Thread.currentThread().getName();
    
                synchronized (this) {
                    getData1 = privateGetData1;
                    getData2 = privateGetData2;
                }
                
                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-1
    长时间处理任务后远程返回的值2 threadName=Thread-0
    end task
    长时间处理任务后远程返回的值1 threadName=Thread-0
    长时间处理任务后远程返回的值2 threadName=Thread-0
    end task
    耗时:3

    通过上述可以看到,当一个线程访问object的一个synchronized同步代码块时,另一个线程仍然可以访问该object对象中的非synchronized(this)同步代码块。

    4、一半同步,一半异步

    不在synchronized块中就是异步执行,在synchronized块中就是同步执行。

    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));
                }
            }
    
        }
    }
    package mythread;
    
    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();
            task.doLongTimeTask();
        }
    
    }
    package mythread;
    
    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();
            task.doLongTimeTask();
        }
    
    }
    package test;
    
    import mytask.Task;
    import mythread.MyThread1;
    import mythread.MyThread2;
    
    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();
        }
    }

    如果非同步的时候会成为交叉打印,同步的话即还排队执行 。

    5、synchronized代码块间的同步性

    在使用synchronized(this)代码块时需要注意的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问被阻塞,这说明synchronized使用的"对象监视器"是一个。

    package doubleSynBlockOneTwo;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public 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(){
                synchronized (this){
                    System.out.println("B begin time ="+System.currentTimeMillis());
                    System.out.println("B end time" + System.currentTimeMillis());
                }
            }
        }
    package doubleSynBlockOneTwo;
    
    import selfThread.ThreadB;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public class ThreadA extends Thread {
    
        private ObjectService service;
        public ThreadA(ObjectService service){
            super();
            this.service=service;
        }
        public void run(){
            super.run();
            service.serviceMethodA();
        }
    }
    package doubleSynBlockOneTwo;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public class ThreadB extends Thread {
    
        private  ObjectService service;
        public ThreadB(ObjectService service){
            super();
            this.service=service;
        }
    
        public void run (){
            super.run();
            service.serviceMethodB();
        }
    }
    package doubleSynBlockOneTwo;
    
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public class Run {
        public static void main(String [] args){
            ObjectService service = new ObjectService();
            ThreadA a = new ThreadA(service);
            a.setName("a");
            a.start();
            ThreadB b = new ThreadB(service);
            b.setName("b");
            b.start();
        }
    }
    A begin time = 1484798392966
    A end time = 1484798394978
    B begin time =1484798394978
    B end time1484798394978

     6、同步synchronized(this)代码块是锁定当前对象的

    package synchronizedthis;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public class Task {
        public void otherMethod(){
            System.out.println("---------------------------------run--otherMethod");
        }
    
        public  void doLongTimeTask(){
            synchronized (this){
                for (int i=0;i<100;i++){
                    System.out.println("synchronized threadName="+Thread.currentThread().getName()+"i="+(i+1));
                }
            }
        }
    }
    package synchronizedthis;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public class MyThread1 extends Thread {
        private Task task;
        public MyThread1(Task task){
            super();
            this.task=task;
        }
        public void run(){
            super.run();
            task.doLongTimeTask();
        }
    }
    package synchronizedthis;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public class MyThread2 extends Thread {
    
        private Task task;
        public MyThread2(Task task){
            super();
            this.task=task;
        }
        public void run(){
            super.run();
            task.doLongTimeTask();
        }
    }
    package synchronizedthis;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    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();
    
        }
    }
    synchronized threadName=Thread-0i=1
    synchronized threadName=Thread-0i=2
    synchronized threadName=Thread-0i=3
    synchronized threadName=Thread-0i=4
    synchronized threadName=Thread-0i=5
    synchronized threadName=Thread-0i=6
    synchronized threadName=Thread-0i=7
    synchronized threadName=Thread-0i=8
    synchronized threadName=Thread-0i=9
    synchronized threadName=Thread-0i=10
    synchronized threadName=Thread-1i=1
    synchronized threadName=Thread-1i=2
    synchronized threadName=Thread-1i=3
    synchronized threadName=Thread-1i=4
    synchronized threadName=Thread-1i=5
    synchronized threadName=Thread-1i=6
    synchronized threadName=Thread-1i=7
    synchronized threadName=Thread-1i=8
    synchronized threadName=Thread-1i=9
    synchronized threadName=Thread-1i=10
  • 相关阅读:
    clickhouse数据文件目录移动到新目录并建立软连接
    时隔七年,来一篇
    微信支付v3版本PHP v3/merchant/media/upload 图片上传
    laravel项目在lnmp环境上线出现404错误
    Linux下sysstat工具学习
    完美快速解决百度分享不支持HTTPS的问题
    微信小程序校验文件在浏览器无法打开
    [Linux]使用宝塔面板做负载均衡时遇到的问题和解决办法
    [Linux]Service mysql start出错(mysql: unrecognized service)解决方法
    Linux的php-fpm优化心得-php-fpm进程占用内存大和不释放内存问题(转)
  • 原文地址:https://www.cnblogs.com/dream-to-pku/p/6296608.html
Copyright © 2011-2022 走看看