Java synchronized解析

多线程三大特性:

可见性、原子性、有序性

synchronize的特性:

1、同一时刻只有一个线程访问临界资源

2、其它未获取到锁执行权的线程必须排队等待

3、保证共享资源的原子性、可见性和有序性

4、进入synchronized范围内自动加锁,synchronized作用域外锁自动消除,即使异常也会释放锁

 synchronize加锁的方式:

  • 对于普通同步方法,锁是当前实例对象。

  • 对于静态同步方法,锁是当前类的Class对象。

  • 对于同步方法块,锁是Synchonized括号里配置的对象。

 

通过具体的例子来看一下

首先是普通方法:

 class NoSyncTest {
        public void method1() {
            Log.i("sync", "method 1 start");
            try {
                Log.i("sync", "method 1 execute");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Log.i("sync", "method 1 end");
        }

        public void method2() {
            Log.i("sync", "method 2 start");
            try {
                Log.i("sync", "method 2 execute");
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Log.i("sync", "method 2 end");
        }
    }

    private void noSyncTest() {
        final NoSyncTest test = new NoSyncTest();

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.method1();
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.method2();
            }
        });

        thread1.start();
        thread2.start();
    }

这是一个没有任何同步的方法,NoSyncTest这个类有两个方法method1和method2,分别执行睡3s和0.5s的动作,然后再两个线程中分别调用这个类的实例test的两个方法,看一下结果:

 

可以看到method2和method1同时执行,method2因为sleep的时间短所以先结束。

再看一下普通方法同步:

class MethodSyncTest {
        public synchronized void method1() {
            Log.i("sync", "method 1 start");
            try {
                Log.i("sync", "method 1 execute");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Log.i("sync", "method 1 end");
        }

        public synchronized void method2() {
            Log.i("sync", "method 2 start");
            try {
                Log.i("sync", "method 2 execute");
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Log.i("sync", "method 2 end");
        }
    }

    private void MethodSyncTest() {
        final MethodSyncTest test = new MethodSyncTest();

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.method1();
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.method2();
            }
        });

        thread1.start();
        thread2.start();
    

synchronize修饰的method1和method2,其他不变,看一下结果:

method1先执行然后3s之后结束了method2才开始执行。(注意这个地方不能new 不同的对象来调用方法,因为修饰普通方法本质是对对象的同步加锁。

看一下第三种静态同步方法:

 static class StaticMethodSyncTest {
        public static synchronized void method1() {
            Log.i("sync", "method 1 start");
            try {
                Log.i("sync", "method 1 execute");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Log.i("sync", "method 1 end");
        }

        public static synchronized void method2() {
            Log.i("sync", "method 2 start");
            try {
                Log.i("sync", "method 2 execute");
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Log.i("sync", "method 2 end");
        }
        public static synchronized void method3() {
            Log.i("sync", "method 3 start");
            try {
                Log.i("sync", "method 3 execute");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Log.i("sync", "method 3 end");
        }
    }

    private void StaticMethodSyncTest() {
        final StaticMethodSyncTest test1 = new StaticMethodSyncTest();
        final StaticMethodSyncTest test2 = new StaticMethodSyncTest();

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test1.method1();
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test2.method2();
            }
        });
        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                StaticMethodSyncTest.method3();
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }

static修饰方法相当于这个方法是类方法,可以直接通过类名.方法名调用。我们在这new出了test1和test2两个对象分别调用method1和method2,以及通过类名.方法名调用method3,看一下结果

method1、method2、method3顺序执行。(同步静态方法的本质是锁的当前类

posted @ 2018-10-17 11:41  养只柯基萌萌哒  阅读(383)  评论(0编辑  收藏  举报