线程同步-synchronized学习

2017-11-20  本文已影响0人  Android天之骄子

synchronized和static synchronized的区别

synchronized关键字修饰普通方法时,是对当前类的当前对象加上了,也就是对象锁,示例如下

    public synchronized void a() {
        String date= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
        System.out.println("执行A之前的时间" + date);
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println("被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行");
                Thread.sleep(1000);
            }
            String dateAfter= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
            System.out.println("执行A之后的时间" + dateAfter);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void b() {
        try {
            String date= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
            System.out.println("执行B之前的时间" + date);
            for (int i = 0; i < 5; i++) {
                System.out.println("被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行");
                Thread.sleep(1000);
            }
            String dateAfter= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
            System.out.println("执行B之后的时间" + dateAfter);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("被Synchronized关键字修饰的普通方法>>>>> B");
    }

我们用关键字synchronized修饰了普通方法AB,并让A、B方法都执行5s,下面看执行测试代码

    public static void main(String[] args) {
        SynchronizedDemo synchronizedOne = new SynchronizedDemo();
        SynchronizedDemo synchronizedTwo = new SynchronizedDemo();

        Thread one = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronizedOne.a();
               // synchronizedOne.c();
            }
        });
        Thread two = new Thread(new Runnable() {
            @Override
            public void run() {
                    try {
                        //休眠 为了A先执行
                        Thread.sleep(1000);
                        synchronizedOne.b();
                         //    synchronizedTwo.d();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }
        });
        one.start();
        two.start();
    }

创建了两个SynchronizedDemo类的对象synchronizedOnesynchronizedTwo,先用同一个对象去执行abe方法,运行效果(在执行B之前休眠1s,为了A先执行)

执行A之前的时间22:29:01
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
执行A之后的时间22:29:06
执行B之前的时间22:29:06
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
执行B之后的时间22:29:11

我们用同一个类的两个对象分类去访问A,B方法看看什么效果

执行A之前的时间22:38:28
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
执行B之前的时间22:38:29
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
执行A之后的时间22:38:33
执行B之后的时间22:38:34
被Synchronized关键字修饰的普通方法>>>>> B

synchronized关键字修饰静态方法时,是对当前加上了锁,也就是类锁,同一时刻只能有一个线程访问该同步方法,其他线程阻塞,示例如下

    public static synchronized  void c() {
        try {
            String date= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
            System.out.println("执行C之前的时间" + date);
            for (int i = 0; i < 5; i++) {
                System.out.println("被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行");
                Thread.sleep(1000);
            }
            String dateAfter= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
            System.out.println("执行C之后的时间" + dateAfter);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static synchronized void d() {
        System.out.println("被Synchronized关键字修饰的静态方法>>>>> D");
    }

static synchronized修饰c,d方法,执行测试

  Thread one = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronizedOne.c();
            }
        });
        Thread two = new Thread(new Runnable() {
            @Override
            public void run() {
                    try {
                        //休眠 为了C先执行
                        Thread.sleep(1000);
                        synchronizedTwo.d();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }
        });
        one.start();
        two.start();

运行结果

执行C之前的时间22:57:15
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
执行C之后的时间22:57:20
被Synchronized关键字修饰的静态方法>>>>> D

总结

同步方法与同步代码块的区别

同步方法的作用范围较大,会同步对象中所有的同步方法的代码。
同步代码块控制范围较小,只会同步代码块中的代码,而代码块意外的代码还是可以被多个线程同时访问的

测试代码

测试代码

上一篇 下一篇

猜你喜欢

热点阅读