synchronized三种使用方式

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/man_8211/article/details/72932023

前言

在多线程并发编程中Synchronized一直是元老级角色,大家都知道synchronized是重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,与lock相比性能相差并不是很大,还是比较建议同步的时候优先使用synchronized。

三种使用方式

  • 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁

  • 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁

  • 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁,同步代码块主要有三种方式 :synchronized(this)、synchronized (obj)、synchronized(Object.class),这三种方式分别是指同步本对象、同步其它对象、同步某个类。

  • 修饰非静态实列方法

public class SynchronizedDemo {

    public static void main(String[] args) {
        SynchronizedDemo demo1 = new SynchronizedDemo();
        // 修饰对象实列方法 锁定的当前实列对象 必须是公用同一个对象才行
        new Thread("thread1"){

            @Override
            public void run(){
                try {
                    demo1.demo1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread("thread2"){

            @Override
            public void run(){
                try {
                    demo1.demo1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }

    /**
     * 修饰实列方法
     * @throws InterruptedException 
     */
    public synchronized void demo1() throws InterruptedException{
        System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
        //休眠2s 造成两个线程同时访问本实列方法
        Thread.sleep(2000);
    }
  • 修饰静态方法 同步的是方法所在的类对象
public class SynchronizedDemo {

    public static void main(String[] args) {
        /**
         * 修饰对象静态方法
         * 静态方法是类方法 静态方法即类方法,它属于一个类而不是某个对象
         * 在其上面加锁 锁的对象为类对象
         */
        new Thread("thread2-1"){

            @Override
            public void run(){
                try {
                    SynchronizedDemo.demo2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread("thread2-2"){

            @Override
            public void run(){
                try {
                    SynchronizedDemo.demo2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }


    /**
     *修饰静态方法 
     * @throws InterruptedException 
     */
    public synchronized static void demo2() throws InterruptedException{
        System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
        Thread.sleep(2000);
    }
}
  • 修饰代码块 同步代码块主要有三种方式 :synchronized(this)、synchronized (obj)、synchronized(Object.class),这三种方式分别是指同步本对象、同步其它对象、同步某个类。
public class SynchronizedDemo {

    public static void main(String[] args) {
        /**
         * 修饰当前对象代码块
         * 锁的调用方法的当前对象
         * 代码块 this代表当前对象 
         * 3与1 2 不是同一个对象 13同时执行 12是同步执行
         */
        SynchronizedDemo block = new SynchronizedDemo();
        new Thread("thread1-1"){

            @Override
            public void run(){
                try {
                    new SynchronizedBlock(block).demo3();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread("thread1-2"){

            @Override
            public void run(){
                try {
                    new SynchronizedBlock(new SynchronizedDemo()).demo3();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread("thread1-3"){

            @Override
            public void run(){
                try {
                    new SynchronizedBlock(block).demo3();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

        /**
         * 修饰对象实列方法-代码块-指定对象
         * 这里new了两个SynchronizedBlock对象 但由于指定同步对象是SynchronizedDemo
         * 所以方法依然会同步执行
         */
        SynchronizedDemo demo4 = new SynchronizedDemo();
        new Thread("thread4-1"){

            @Override
            public void run(){
                try {
                    new SynchronizedBlock(demo4).demo3_1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread("thread4-2"){

            @Override
            public void run(){
                try {
                    new SynchronizedBlock(demo4).demo3_1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

        /**
         * 修饰代码块-class
         * 这里new了两个SynchronizedDemo对象 但锁的是类对象
         * 所以方法依然会同步执行
         */
        new Thread("thread3-1"){

            @Override
            public void run(){
                try {
                    new SynchronizedBlock(new SynchronizedDemo()).demo3_2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread("thread3-2"){

            @Override
            public void run(){
                try {
                    new SynchronizedBlock(new SynchronizedDemo()).demo3_2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

class SynchronizedBlock {
    //声明一个实例变量
    private SynchronizedDemo demo;
    SynchronizedBlock(SynchronizedDemo demo){
         this. demo= demo;
    }
    /**
     * 同步当前对象
     * @throws InterruptedException
     */
    public void demo3() throws InterruptedException{
        synchronized(this){
            System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
            Thread.sleep(2000);
        }
    }
    /**
     * 同步指定对象
     * @throws InterruptedException
     */
    public void demo3_1() throws InterruptedException{
        synchronized(demo){
            System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
            Thread.sleep(2000);
        }
    }
    /**
     * 同步class类对象
     * @throws InterruptedException
     */
    public void demo3_2() throws InterruptedException{
        synchronized(SynchronizedDemo.class){
            System.out.println("当前访问的线程名称是===="+Thread.currentThread().getName());
            Thread.sleep(2000);
        }
    }
}

总结

  • 在多线程环境中,可以使用synchronized关键字对资源进行同步,synchronized关键字可以同步方法和代码块,同步的是对象或者类,而不是代码。
  • 一个对象中的同步方法一次只能被一个线程访问,如果有多个同步方法,一个线程一次也只能访问其中的一个同步方法,但是非同步方法不受任何影响。
  • 同步是通过加锁的形式来控制的,让一个线程访问一个同步方法时会获得这个对象的锁,只有退出同步方法时才会释放这个锁,其它线程才可访问
展开阅读全文

没有更多推荐了,返回首页