(一) java 关键字之 synchronized用法解析

synchronized同步锁,用synchronized修饰的方法,当有线程执行到这个方法时,都要检查以下有没有别的线程正在使用这个方法。以确保每刻始终只有一个线程执行这个方法。

根据synchronized作用的范围不同,可以分为以下两种:

1、作用于方法
2、作用于代码块

作用与方法时,可以用分为作用于普通方法和静态方法;作用于代码块有作用于实例对象、类对象和任意实例对象三种。

public class Test {
    //注意,静态方法是作用于类而不是对象的,因此这里锁作用于Test.class类;不论new了几个实力对象,也都是只能获得一个锁。
    public static synchronized void Method1() {
        ...
    }

    //实例方法,锁住的是该类的一个实例对象;因此如果new了两个实例对象,那么也将会获得不同的锁。
    public synchronized void method2() {
        ...
    }

    public void method3() {
        //同步代码块,锁住的是类对象
        synchronized (Test.class) {
            ...
        }
    }

    public void method4() {
        //同步代码块,锁住的是类的实例对象
        synchronized (Test.this) {
            ...
        }
    }

    public void metho5(Object object) {
        //同步代码块,锁住的是配置的实例对象
        synchronized (object) {
            ...
        }
    }
}


对于类这个级别加锁有些太过于粗糙,因此可以在使用中对代码块进行加锁。

上面的分类也常常认为是三种:
1、在普通实例方法中使用;
2、在静态方法中使用;
3、在代码块中使用。

下面就对上面这三种作用情况分别举例子进行验证,再对运行结果进行分析:

0、先看一下不使用synchronized时的情况

  class SynchronizedTest implements Runnable{
          boolean flag = true;
//        static SynchronizedTest test =  new SynchronizedTest();

        public void method1() {
//            synchronized (this) {
                Log.e("start", ">>>>>");

                if (flag) {
                    Log.e("execute", ">>>>>");
                    flag = false;
                }
                Log.e("end", ">>>>>");
//            }
        }

        @Override
        public void run() {
//            method1();

                method1();

         }
    }

调用

		 final SynchronizedTest test1 = new SynchronizedTest();
        final SynchronizedTest test2 = new SynchronizedTest();

        Thread thread1 = new Thread(test1);
        Thread thread2 = new Thread(test2);

//        thread1.sleep(3000);
        thread1.start();
        thread2.start();

运行结果
在这里插入图片描述
可以看到如果不加锁,两个线程几乎是一起运行的,也没有先后问题的区分,更没有一个线程需要等待另一个线程运行结束再运行的情况。

1、在实例方法中使用

    class SynchronizedTest implements Runnable{
          boolean flag = true;
//        static SynchronizedTest test =  new SynchronizedTest();

        public synchronized void method1() {
//            synchronized (this) {
                Log.e("start", ">>>>>");

                if (flag) {
                    Log.e("execute", ">>>>>");
                    flag = false;
                }
                Log.e("end", ">>>>>");
//            }
        }

        @Override
        public void run() {
                method1();
         }
    }

调用

		final SynchronizedTest test1 = new SynchronizedTest();
        final SynchronizedTest test2 = new SynchronizedTest();

        Thread thread1 = new Thread(test1);
        Thread thread2 = new Thread(test2);

//        thread1.sleep(3000);
        thread1.start();
        thread2.start();

运行结果
在这里插入图片描述
这里可以看到,虽然加了锁,但是程序的运行结果并没有像我们想象的那样,这是因为在调用的时候,是new了两个实例对象,因此锁是对两个不同的对象加的,是相互不干扰的。
因此,在实例方法中使用应该是两个线程对于同一个实例方法进行操作
将调用部分的代码修改为:

        final SynchronizedTest test1 = new SynchronizedTest();
//        final SynchronizedTest test2 = new SynchronizedTest();

        Thread thread1 = new Thread(test1);
        Thread thread2 = new Thread(test1);

//        thread1.sleep(3000);
        thread1.start();
        thread2.start();

运行结果
在这里插入图片描述
这样也就达到了第一个线程运行完全结束再运行第二个线程的目的。

2、在静态方法中使用

static class SynchronizedTest implements Runnable{
          static boolean flag = true;
//        static SynchronizedTest test =  new SynchronizedTest();

        public static synchronized void method1() {
//            synchronized (this) {
                Log.e("start", ">>>>>");

                if (flag) {
                    Log.e("execute", ">>>>>");
                    flag = false;
                }
                Log.e("end", ">>>>>");
//            }
        }

        @Override
        public void run() {
                method1();
         }
    }

调用

		 final SynchronizedTest test1 = new SynchronizedTest();
        final SynchronizedTest test2 = new SynchronizedTest();

        Thread thread1 = new Thread(test1);
        Thread thread2 = new Thread(test2);

//        thread1.sleep(3000);
        thread1.start();
        thread2.start();

运行结果
在这里插入图片描述
在静态方法中,也new了两个对象,但是运行结果不同于上面在实例方法中的,这是因为静态是针对类而不是对象的,也就是说不管是test1还是test2,他们都是SynchronizedTest类,synchronized锁是加在类范畴的。所以不管new了几个对象,在静态的修饰下都是只能获取一个锁的。

3、在代码块中使用

static class SynchronizedTest implements Runnable{
		 static boolean flag = true;
        static SynchronizedTest test =  new SynchronizedTest();

        public void method1() {
                Log.e("start", ">>>>>");

                if (flag) {
                    Log.e("execute", ">>>>>");
                    flag = false;
                }

                Log.e("end", ">>>>>");
        }

        @Override
        public void run() {
            synchronized (test){
                method1();
            }
        }
    }

在主函数调用

       Thread thread1 = new Thread(SynchronizedTest.test);
        Thread thread2 = new Thread(SynchronizedTest.test);

//        thread1.sleep(3000);
        thread1.start();
        thread2.start();

运行结果
在这里插入图片描述
运行结果可以看出来,当临界值flag改变时,第二个线程对应的flag也就发生了改变。

.
.
.
欢迎交流和指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值