【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

目录

 

线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

1.互斥

2.线程同步与synchronized(this)语句

3.死锁与synchronized(非this)语句


线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

1.互斥

synchronized关键字在修饰方法时保证任何时刻只有一个线程在运行此方法。

但存在一个问题。如果现在有两个线程:一个plus,一个minus.

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

两个线程同时执行run中的opr方法,而该方法中有两个并列的if语句嵌套的无限循环(休眠语句便于最后输出结果的展示,否则输出太快看不到):

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

运行程序:(因为在有参构造myCalc对象的同时,对两个线程进行了实例化,在这里就可以直接调用线程的方法)

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

结果:只有plus线程访问到了该方法,因为我们设置了方法的互斥访问,同时刻只有一个线程在访问,但是因为其中有无限循环语句,则此线程永远不会退出访问。所以另一线程一直在等待。

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

这时出现了问题。我们要想用两个线程交替访问一个方法,而不出现此情况该怎么实现呢?运用到线程同步的理论。

2.线程同步与synchronized(this)语句

同样的在Runnable接口的实现类中声明两个线程(如果直接在Thread子类中声明线程和重修run方法,则只能实现多线程执行多个独立方法,而无法实现多线程并行执行同一个方法),

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

对run进行重写:

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

线程printA访问第一个if语句块,线程printB访问第二个if语句块。

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

同步的实现首先要使用:synchronized(this){  },作用:当对象访问到这个语句时,锁定这个对象访问的这块代码,访问代码期间,只能该对象访问,其他对象不能访问。

注意:线程也是一个对象。

程序运行:

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

由此可知程序的运行流程大概是:

java程序是顺序执行的:

线程printA运行到第一个if语句块——>成功(锁定)——> 唤醒 ———>执行——>阻塞让出————————>阻塞——>阻塞—————>阻塞——>阻塞(等唤醒)

线程printB运行到第一个if语句块——>等待(排斥)——>等待————>等待——————>访问第一个if语句块失败——>访问第二个if语句块———>成功(锁定)

两个线程交替执行方法

结果:

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

3.死锁与synchronized(非this)语句

死锁是程序无法执行却无逻辑错误的一种情况

当两个线程分别运行两个独立的方法是不会出现死锁现象的(各运行各的),那么我们怎么能让两个线程互相牵制来模拟出死锁的现象呢?

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

首先我们声明两个静态的成员对象并实例化,或者说两个引用的实例化。(Object类是所有类的父类)。

用这两个对象来牵制两条线程。这两个对象像两把锁,而两个独立的方法像两扇门。对应的锁打开对应的门。

来看两个方法:

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

【Java编程由浅入深】线程互斥、同步与死锁——synchronized(this)&synchronized(非this)

threada线程访问PrintA方法,threadb访问PrintB方法。

假设threada线程先执行。

threada线程执行到synchronized(MyLock.lock1){ }时,类中的静态成员lock1被锁定了,因为静态成员只能实例化一次,所以相当于成员(钥匙)是固定唯一的(对于静态成员的所有的操作都是基于类的操作,相对于直接对模板进行操作);但这个钥匙被threada线程拿走了(锁定了)。这时threadb线程执行到synchronized(MyLock.lock2){ }时,类中的静态成员lock2被锁定了,这时两把钥匙都被拿走了。而当threada线程想离开synchronized(MyLock.lock1){ }代码块然后进入下面的代码块时,必须要有lock2这把钥匙,当threadb线程想离开synchronized(MyLock.lock2){ }代码块然后进入下面的代码块时,必须要有lock1这把钥匙。他们通过类访问两个对象时,发现都被锁定了,但他们只有拿到新钥匙才能离开,而自己需要的钥匙却在对方的手中。此时,程序出现了死锁。