面试

Synchronized总结

2017-11-20  本文已影响4人  落魄的安卓开发

java中多线程中的同步机制会对资源进行加锁,保证在同一时间只有一个线程可以操作资源,避免多线程同时访问相同资源发生冲突。

Synchronized是java中的关键字,它是一种同步锁,可以实现同步机制

Synchronized修饰对象主要有以下三种:

  1. 修饰普通方法

    • 一个对象中的加锁方法只允许一个线程访问。但要注意‘这种情况下锁的是访问该方法的实例对象,如果多个线程不同对象访问该方法,则无法保证同步
  2. 修饰静态方法

    • 由于静态方法是类方法,所以这个方法锁的是包含这个方法的类,也就是类对象;这样如果多个线程不同的对象访问该静态方法,也是可以保证同步的。
  3. 修饰代码块

    • 修饰普通代码块和修饰普通方法一样;
    • Synchronized静态代码块它的同步效果和修饰方法类似
    • 其中Synchronized(obj)这里的obj可以为类的一个属性、也可以是当前的对象。

Synchronized修饰方法和代码块的区别:

Synchronized方法控制范围较大,它会同步对象中所有的Synchronized方法的代码。

Synchronized代码块控制范围较小,它只会同步代码块中的代码,而位于代码块之外的代码是可以被多个线程访问的。

简单来说 就是Synchronized代码块更加灵活精确。

测试代码如下:

private SynchronizedTest synchronizedTest;

private void testSynchrnoized() {
    synchronizedTest = new SynchronizedTest();
    //测试synchronized修饰普通方法
    //testCommon();
    //测试synchronized修饰静态方法
    //testStatic();
    //测试synchronized修饰代码块
    testArea();
}

private void testArea() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            synchronizedTest.setAge2(0);
        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            SynchronizedTest test = new SynchronizedTest();
            test.setAge2(1);
        }
    }).start();
}

private void testStatic() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            synchronizedTest.setAge1(0);
        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            SynchronizedTest test = new SynchronizedTest();
            test.setAge1(1);
        }
    }).start();
}

private void testCommon() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            synchronizedTest.setAge(0);
        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            synchronizedTest.setAge(1);
        }
    }).start();
}

SynchronizedTest类代码如下:

public class SynchronizedTest {

    public int age;

    public int getAge() {
        return age;
    }

    /**
     * 修饰普通方法:一个对象中的加锁方法只允许一个线程访问。但要注意‘这种情况下锁的是访问该方法的实例对象,如果多个线程不同对象访问该方法,则无法保证同步’
     *
     * @param age
     */
    public synchronized void setAge(int age) {
        if (age == 0) {
            Log.e("result", "Thread0进来访问了");
        } else {
            Log.e("result", "Thread1进来访问了");
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * 修饰静态方法: 由于静态方法是类方法,所以这个方法锁的是包含这个方法的类,也就是类对象;这样如果多个线程不同的对象访问该静态方法,也是可以保证同步的。
     *
     * @param age
     */
    public synchronized static void setAge1(int age) {
        if (age == 0) {
            Log.e("result", "Thread0进来访问了");
        } else {
            Log.e("result", "Thread1进来访问了");
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static SynchronizedTest instance;
    public static  SynchronizedTest getInstance(){
        if(instance == null){
            synchronized (SynchronizedTest.class){
                instance = new SynchronizedTest();
            }
        }
        return instance;
    }

    /**
     * 修饰代码块:
     *          1. 修饰普通代码块和修饰普通方法一样;
     *          2. Synchronized静态代码块它的同步效果和修饰方法类似
     *          3. 其中Synchronized(obj)这里的obj可以为类的一个属性、也可以是当前的对象。
     * @param age
     */
    public static void setAge2(int age) {
        synchronized (SynchronizedTest.class) {
            if (age == 0) {
                Log.e("result", "Thread0进来访问了");
            } else {
                Log.e("result", "Thread1进来访问了");
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读