【Java】【多线程】同步方法和同步代码块、死锁

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/love_Aym/article/details/79965406

转载:https://blog.csdn.net/u010002184/article/details/72566874?locationNum=11&fps=1

一、java的内置锁

        每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。

    获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。

    java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,知道线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

  • java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的,对象锁是用于对象非静态实例方法,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。

二、同步

1、同步代码块

  • 用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
  • 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的。锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
class Printer {
	Demo d = new Demo();
	public static void print1() {
	    synchronized(d){	           //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
		System.out.print("黑");
		System.out.print("马");
		System.out.print("程");
		System.out.print("序");
		System.out.print("员");
		System.out.print("\r\n");
		}
	}
	
	public static void print2() {	
	    synchronized(d){	
		System.out.print("传");
		System.out.print("智");
		System.out.print("播");
		System.out.print("客");
		System.out.print("\r\n");
		}
	}
}

2、同步方法

  • 使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的

  • 非静态方法的锁机制为this
  • 静态方法的锁机制为字节码对象,类名.class
class Printer {
    public static void print1() {
	synchronized(Printer.class){				//锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
		System.out.print("黑");
		System.out.print("马");
		System.out.print("程");
		System.out.print("序");
		System.out.print("员");
		System.out.print("\r\n");
		}
	}	
	/*
	* 非静态同步函数的锁是:this
	* 静态的同步函数的锁是:字节码对象
	*/
    public static synchronized void print2() {	
	System.out.print("传");
		System.out.print("智");
		System.out.print("播");
		System.out.print("客");
		System.out.print("\r\n");
		}
	}

转载1:https://blog.csdn.net/zhenwodefengcaii/article/details/54601098(棒)

    Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

     1、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
   2、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
  3、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
    4、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
    5、以上规则对其它对象锁同样适用.

其他更多解释,直接看链接~~~~


转载2:https://www.cnblogs.com/sgzs/archive/2017/12/01/7943647.html

深刻通俗理解:

虽然写法不同,但实际上,只有一种,就是【同步代码块】。这是核心核心核心。同步方法也是同步代码块。

同步就是:一个对象同一时间只能为一个同步代码块服务

同步代码块需要传递的对象(锁对象):就是锁住这个对象,表示这个对象正在为我服务,其他人不能用(非synchronized代码块、方法除外)。

同步方法:就是同步代码块,同步锁对象是this

同步静态方法:就是同步代码块,同步锁对象是类的class对象(Demo类里的静态方法锁对象就是Demo.class)

OK了,这就是同步原理。再说简单点(当一个对象被锁住之后,在该代码块之外去使用此对象的方法,只要遇到同步代码块,就会进入等待状态)


四、死锁

多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁。

第一个线程中需获取第二个线程,第二个线程执行时需获取第一个线程,而此时第一个线程还没执行完没被释放,此时就陷入了僵持状态,进入死锁。


五、回顾以前说过的线程安全问题

    * 看源码:Vecto,StringBuffer,Hashtable,Collections.synchroinzed(xxx)

  •  Vector是线程安全的,ArrayList是线程不安全的;
  • StringBuffer是线程安全的,StringBuilder是线程不安全的;
  •  Hashtable是线程安全的,HashMap是线程不安全的。



阅读更多
想对作者说点什么?

博主推荐

换一批

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