线程同步-synchronized学习

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
  • 当用同一个对象正在访问该类中被Synchronized修饰的普通方法时,其他线程的当前对象不可访问该类的其他同步方法

我们用同一个类的两个对象分类去访问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方法是不相干扰的。也就是说,其它线程可以同时访问同一个类的另一个对象的synchronized方法;

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

总结

  • 修饰普通方法:普通方法属于对象性方法,该同步锁属于对象锁,多个线程中同一个对象访问同步方法,只能有一个线程访问,多个线程多个对象可以同时访问该同步方法
  • 修饰静态方法:静态方法属于类方法,该同步锁属于类锁,多个线程多个对象只能有一个线程可以访问该同步方法,因为字节码文件只有一个。
  • 修饰代码块:有Synchronized(obj)和Synchronized(obj.class)两种代码块,前者同修饰普通方法一样,或者同修饰静态方法一样。

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

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

测试代码

测试代码

你可能感兴趣的:(线程同步-synchronized学习)