JAVA基础多线程(一)synchronized关键字

参考了博客::http://www.cnblogs.com/skywang12345/p/3479202.html

synchronized

概述

Java中每一个对象有且仅有一个与之关联的锁,这种锁成为内部锁,内部锁是一种排它锁(又称互斥锁,一个锁只能被一个线程持有),内部锁是通过synchronized关键字实现的,它可以用来修饰方法和代码块。synchronized修饰的方法叫做同步方法,修饰的静态方法称为同步静态方法,修饰的代码块称为同步块。

synchronized锁的是对象

基本规则

  1. 当一个线程访问某对象的synchronized方法或synchronized代码块时,其他线程可以访问该对象非synchronized修饰的方法和代码块
  2. 当一个线程访问某对象的synchronized方法或synchronized代码块时,其他线程对该对象该synchronized方法和代码块访问将被阻塞。
  3. 当一个线程访问某对象的synchronized方法或synchronized代码块时,其他线程对该对象其他synchronized方法和代码块访问将被阻塞。

验证规则1

public static void main(String[] args) {
        Inner inner = new Inner();
        new Thread(() -> {
            try {
            	//执行同步方法
                inner.synMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
            	//执行非同步方法
                inner.commonMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

class Inner {

    public synchronized void synMethod() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "--synMethod");
            Thread.sleep(100);
        }
    }

    public void  commonMethod() throws InterruptedException {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "--commonMethod");
                Thread.sleep(100);
		}
    }

执行结果:

Thread-0--synMethod
Thread-1--commonMethod
Thread-0--synMethod
Thread-1--commonMethod
Thread-0--synMethod
Thread-1--commonMethod
Thread-0--synMethod
Thread-1--commonMethod
Thread-1--commonMethod
Thread-0--synMethod

验证规则2

public static void main(String[] args) {
        Inner inner = new Inner();
        Inner inner2 = new Inner();

        new Thread(() -> {
            try {
                inner.synMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();


        new Thread(() -> {
            try {
                inner.synMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

class Inner {
    
    public synchronized void synMethod() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "--synMethod");
            Thread.sleep(100);
        }
    }
}

验证结果

Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-1--synMethod
Thread-1--synMethod
Thread-1--synMethod
Thread-1--synMethod
Thread-1--synMethod

验证规则3

public static void main(String[] args) {
        Inner inner = new Inner();
        Inner inner2 = new Inner();

        new Thread(() -> {
            try {
                inner.synMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();


        new Thread(() -> {
            try {
                inner.synBlock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
}


class Inner {
    
    public synchronized void synMethod() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "--synMethod");
            Thread.sleep(100);
        }
    }

    public void synBlock() throws InterruptedException {
    	//获得的是this对象的锁,也就是当前访问对象
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "--synBlock");
                Thread.sleep(100);
            }
        }
    }
}

验证结果:

Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-0--synMethod
Thread-1--commonMethod
Thread-1--commonMethod
Thread-1--commonMethod
Thread-1--commonMethod
Thread-1--commonMethod

如果我们将synBlock中锁的对象this换成其他对象

class Inner {
	private final Object obj = new Object();
    public void synBlock() throws InterruptedException {
        //synchronized (this) {
        synchronized (obj) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "--synBlock");
                Thread.sleep(100);
            }
        }
    }
}

此时启动main方法的结果是异步执行,原因在于获取的对象锁不同,因为synchronized (obj)中获取的是obj对象的锁,同步方法则获取的是this对象的锁

全局锁和对象锁

对象锁:获取的是某个对象对应唯一关联的锁,如果对象是单例则也是全局锁。如非静态方法的synchronized关键字获取的就是对象锁
全局锁:该锁针对的是类对象,java中万物皆对象,类也是有对应的对象,例如静态方法的synchronized获得的锁是类对象,看例子:

	public static void main(String[] args) {
        Inner inner = new Inner();
        new Thread(() -> {
            try {
                Inner.synStaticMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                inner.synBlock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

class Inner{
    public synchronized static void synStaticMethod() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "--synStaticMethod");
            Thread.sleep(100);
        }
    }
    public void synBlock() throws InterruptedException {
        synchronized (Inner.class) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "--synBlock");
                Thread.sleep(100);
            }
        }
    }
}

运行结果

Thread-0--synStaticMethod
Thread-0--synStaticMethod
Thread-0--synStaticMethod
Thread-0--synStaticMethod
Thread-0--synStaticMethod
Thread-1--synBlock
Thread-1--synBlock
Thread-1--synBlock
Thread-1--synBlock
Thread-1--synBlock

Inner.synStaticMethod();调用的是静态同步方法,获得的是Inner类对象对应的锁,与synchronized (Inner.class)获得的是同一个锁,类对象是全局唯一的,所以类对象类对象对应的锁也叫全局锁

参考别人博客拿来的一个例子:

	public synchronized void isSyncA(){}
    public synchronized void isSyncB(){}
    public static synchronized void cSyncA(){}
    public static synchronized void cSyncB(){}

假设,Something有两个实例x和y。分析下面4组表达式获取的锁的情况。

(01) x.isSyncA()与x.isSyncB()
(02) x.isSyncA()与y.isSyncA()
(03) x.cSyncA()与y.cSyncB()
(04) x.isSyncA()与Something.cSyncA()

(1)不能被同时访问,因为访问的都是对象x的同步锁。
(2)可以被同时访问,因为访问的不是同个对象的同步锁。
(3)不能被同时访问,实例化对象调用静态方法和类名直接访问是相同的,但是不建议使用实例化对象因为会增加编译器解析成本。
(4)可以被同时访问, x.isSyncA()访问的是x对象的同步锁,Something.cSyncA()访问的是全局锁

synchronized同步方法和代码块的区别

当synchronized修饰普通(非静态)方法时,执行它需要获得是执行该方法的对象的锁,也就是常说的this,所以使用synchronized修饰的方法的效果和在方法中使用synchronized修饰代码块锁定this对象的效果是相同的。如下代码所示

public synchronized void synMethod()  { 
	//逻辑代码
}

public void synBlock() {
	synchronized (this) {
	//逻辑代码
	}
}

当synchronized修饰静态方法时,执行时获得的是类对象的锁,下面两个方法获得的锁对象都是类对象对应的锁。

	public synchronized static void synStaticMethod() throws InterruptedException {
        //代码逻辑
    }
    public void synBlock() throws InterruptedException {
        synchronized (Inner.class) {
            //代码逻辑
        }
    }

总结

synchronized关键字访问的锁是对象锁,这是它的核心,判断是否能够异步执行也就是判断访问的锁对象是否相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值