java线程属性_【java 线程】java线程之重入

在java的多线程领域,有一种机制叫作“重入”。都知道在java处理多线程的程序中,为了确保共享数据的准确性,避免失效,通常会对共享数据进行“加锁”。有一种加锁方式为对属性或者方法加上synchronized修饰符,表示对此属性或者方法的操作属于原子性。所谓原子性,就是在多线程都要访问此属性或者方法时,某个线程对属性或者方法的相关操作都执行完毕,产生结果之后,其他的线程才可以对此属性或者方法进行操作。

而synchronized之所以能做到对属性或者方法的原子性的操作,是因为synchronized对属性或者方法锁上了一道门,而只有持有特定锁的线程才可以访问,并且在访问期间,这道门是上锁的状态,其他的线程在没有得到这道门的特定锁情况下,是没有权限访问属性或者方法的。而想要得到锁,必须等拥有此锁的线程做完所有相关操作并释放锁后,才能得到锁,并对属性或方法做相关的操作。

用synchronized加锁有两种方式,一种是同步块,一种是同步方法。

同步快

把方法中的代码块用synchronized关键字“括住”。此种做法需要显示地声明“锁”,看下面代码

String strLock = "";

public void leave(){

synchronized (strLock){

System.out.println(Thread.currentThread().getName()+"我先来的,等我取完钱了");

try {

System.out.println(Thread.currentThread().getName()+"我也好困,睡会吧");

Thread.sleep(2000);

System.out.println(Thread.currentThread().getName()+"睡醒了,要走了");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

上面代码就是“同步快”的写法,而声明的strLock就是“同步快”持有的“锁”。“同步快”必须要这种格式显示地声明“持有锁”。

同步方法

用synchronized修饰的方法称为“同步方法”,此种方法不需要显示的声明锁,看下面代码

public synchronized void come(){

try {

System.out.println(Thread.currentThread().getName()+"我今夜来到ATM前");

System.out.println(Thread.currentThread().getName()+"由于时间太晚了,所以就睡了一觉");

Thread.sleep(1000);

System.out.println(Thread.currentThread().getName()+"睡醒了,要取钱了");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

“同步方法”隐式地声明了锁,而“锁”就是this,即“同步方法”所属的对象。

重入

所谓“重入”,即当持有“锁”的线程想要访问另一个被“相同锁”锁住的“同步方法”或者“同步块”时,不必等到“锁”释放即可访问。先看下面代码

package altsd.thread;

public class Bank {

String strLock = "";

public synchronized void come(){

try {

System.out.println(Thread.currentThread().getName()+"我今夜来到ATM前");

System.out.println(Thread.currentThread().getName()+"由于时间太晚了,所以就睡了一觉");

Thread.sleep(1000);

System.out.println(Thread.currentThread().getName()+"睡醒了,要取钱了");

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (strLock){

System.out.println(Thread.currentThread().getName()+"我正在取钱");

}

}

public void leave(){

synchronized (strLock){

System.out.println(Thread.currentThread().getName()+"我先来的,等我取完钱了");

try {

System.out.println(Thread.currentThread().getName()+"我也好困,睡会吧");

Thread.sleep(2000);

System.out.println(Thread.currentThread().getName()+"睡醒了,要走了");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

这段代码中,有个“同步方法”come()被this锁“锁住”,“同步方法”中有个“同步快”,用的是另一个对象“strLock”;在leave()方法中有一个“同步块”被“strLock”锁住。另有两个线程

Thead1:访问bank的come()方法,代码如下

package altsd.thread;

public class Thread1 implements Runnable{

Bank bank = new Bank();

@Override

public void run() {

bank.come();

}

}

Thead2:访问bank的leave()方法,代码如下

package altsd.thread;

public class Thread2 implements Runnable {

Bank bank = new Bank();

@Override

public void run() {

bank.leave();

}

}

在主线程中运行这两个线程会发生什么呢?

package altsd.thread;

public class TestThread {

public static void main(String[] args) {

Thread t1 = new Thread(new Thread1());

t1.setName("小明");

Thread t2 = new Thread(new Thread2());

t2.setName("小红");

t1.start();

t2.start();

}

}

结果如下:

小明我今夜来到ATM前

小明由于时间太晚了,所以就睡了一觉

小红我先来的,等我取完钱了

小红我也好困,睡会吧

小明睡醒了,要取钱了

小红睡醒了,要走了

小明我正在取钱

首先“小明”访问了come()方法,持有了“this锁”,但途中睡了一会儿;此时“小红”在“小明”睡觉的时候访问leave()方法,持有了“strLock锁”,这时“小红”也睡了一会儿。当“小明”醒来,想访问“同步块”时,发现“strLock锁”还被小红拿着,没办法访问,只好等“小红”醒来再访问“同步块”。

如果没有让Bank对象中的“同步方法”和“同步块”都被“this锁”锁住,会发生什么呢?看下面代码

package altsd.thread;

public class Bank {

String strLock = "";

public synchronized void come(){

try {

System.out.println(Thread.currentThread().getName()+"我今夜来到ATM前");

System.out.println(Thread.currentThread().getName()+"由于时间太晚了,所以就睡了一觉");

Thread.sleep(1000);

System.out.println(Thread.currentThread().getName()+"睡醒了,要取钱了");

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (this){

System.out.println(Thread.currentThread().getName()+"我正在取钱");

}

}

public void leave(){

synchronized (this){

System.out.println(Thread.currentThread().getName()+"我先来的,等我取完钱了");

try {

System.out.println(Thread.currentThread().getName()+"我也好困,睡会吧");

Thread.sleep(2000);

System.out.println(Thread.currentThread().getName()+"睡醒了,要走了");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

这块代码中,“同步方法”和“同步块”都是用的“this锁”,其他程序不变,看结果:

小明我今夜来到ATM前

小红我先来的,等我取完钱了

小明由于时间太晚了,所以就睡了一觉

小红我也好困,睡会吧

小明睡醒了,要取钱了

小明我正在取钱

小红睡醒了,要走了

我们发现,“小明”并没有等“小红”醒来释放“this锁”就可以进入到“同步块”中,这就是“重入”。当多个同步代码持有的“锁”是同一个锁时,则持有此锁的线程可随意进入同步代码中,不论此锁是否被占用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值