synchronized关键字

256 阅读1分钟

概念

synchronized是同步锁,可重入锁

作用在不同地方的不同效果

修饰代码块

修饰以{}包含的代码块,当多个并发线程到达时,只有一个线程能够执行,其他线程则被阻塞等待;synchronized作用的对象(锁定的对象)是调用代码块的实例对象

同一对象加锁

在同一个对象上加锁,多个线程会依次进入代码块

代码展示

public class SynchronizedTest implements Runnable {

    /* int的默认值为0 */
    private int i;

    @Override
    public void run() {

        synchronized (this) {

            for (int j = 0; j < 10; j++) {

                System.out.println(Thread.currentThread().getName() + " : " + (i++));

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {

        SynchronizedTest synchronizedTest = new SynchronizedTest();

        new Thread(synchronizedTest, "t1").start();

        new Thread(synchronizedTest, "t2").start();

    }
}

打印展示

同一对象加锁

不同对象加锁

在不同的对象上加锁,多个线程为交替进入代码块,即无法起到保证代码块被同步调用的效果

代码展示

public class SynchronizedTest implements Runnable {

    /* int的默认值为0 */
    private int i;

    @Override
    public void run() {

        synchronized (this) {

            for (int j = 0; j < 10; j++) {

                System.out.println(Thread.currentThread().getName() + " : " + (i++));

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {

        new Thread(new SynchronizedTest(), "t1").start();

        new Thread(new SynchronizedTest(), "t2").start();

    }
}

打印展示

不同对象加锁

修饰方法

与修饰代码块很相似,只是范围不同;且synchronized关键字不能被继承,即子类若覆盖父类方法,将不再拥有synchronized的特性

修饰静态方法

作用范围是整个静态方法
静态方法属于类,不属于类的实例对象;当synchronized修饰静态方法时,锁定的是类中的所有实例对象

代码展示

public class SynchronizedTest implements Runnable {

    /* int的默认值为0 */
    private static int i;

    public static synchronized void staticMethod() {

        for (int j = 0; j < 10; j++) {

            System.out.println(Thread.currentThread().getName() + " : " + (i++));

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public synchronized void run() {

        staticMethod();

    }

    public static void main(String[] args) {

        new Thread(new SynchronizedTest(), "t1").start();

        new Thread(new SynchronizedTest(), "t2").start();

    }
}

打印展示

修饰静态方法

具有可重入特性

一个加锁的方法里面调用同一对象中另外一个加锁的方法可以直接获取锁,不会阻塞

1.当线程请求由其他线程锁住的方法时,该线程会阻塞,但当请求由自己持有锁的方法时,该请求能够成功,即能重入
2.可重入性适用于继承的场景,如父类方法和子类方法都用synchronized修饰,子类方法调用父类时,也具有可重入特性

代码展示

public class SynchronizedTest extends Thread {

    public static class Synchronized {

        public synchronized void func1() {
            System.out.println("func1方法的线程id: " + Thread.currentThread().getId());
            func2();
        }

        public synchronized void func2() {
            System.out.println("func2方法的线程id: " + Thread.currentThread().getId());
        }
    }

    @Override
    public void run() {
        new Synchronized().func1();
    }

    public static void main(String[] args) {

        new SynchronizedTest().start();

        new SynchronizedTest().start();

    }
}

打印展示

可重入性