Java多线程锁定未能正确工作

huangapple go评论69阅读模式
英文:

Java multithreading lock is not working correctly

问题

完整的程序如下:

import java.util.concurrent.*;
import java.util.concurrent.locks.*;

public class AccountWithConditionsUser {
	private static Account account = new Account();
	public static void main(String[] args) {
		System.out.println("Thread 1\t\tThread 2\t\tBalance");
		ExecutorService executor = Executors.newFixedThreadPool(2);
		executor.execute(new DepositTask());
		executor.execute(new WithdrawTask());
		executor.shutdown();
		while (!executor.isShutdown()) {
		}
	}
	public static class DepositTask implements Runnable{
		public void run() {
			try {
				while (true) {
					account.deposit((int)(Math.random() * 10) + 1);
					Thread.sleep(1000);
				}
			}
			catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		}
	}

	public static class WithdrawTask implements Runnable{
		public void run() {
			while (true) {
				account.withdraw((int)(Math.random() * 10) + 1);
			}
		}
	}

	private static class Account {
		private static Lock lock = new ReentrantLock(true);
		private static Condition newDeposit = lock.newCondition();

		private int balance = 0;
		public int getBalance() {
			return balance;
		}

		public void withdraw(int amount) {
			lock.lock();
			System.out.println("->Withdraw Obtained Lock");
			try {
				while (balance < amount) {
					System.out.println("\t\t\tWait for deposit");
					newDeposit.await();
				}
				balance -= amount;
				System.out.println("\t\t\tWithdraw " + amount + "\t\t" + getBalance());
			}
			catch (Exception e) {
				e.printStackTrace();
			}
			finally {
				System.out.println("->Withdraw Released Lock");
				lock.unlock();
			}
		}

		public void deposit(int amount) {
			lock.lock();
			System.out.println("->Deposit Obtained Lock");
			try {
				balance += amount;
				System.out.println("Deposit " + amount + "\t\t\t\t\t" + getBalance());
				newDeposit.signalAll();
			}
			catch (Exception e) {
				e.printStackTrace();
			}
			finally {
				System.out.println("->Deposit Released Lock");
				lock.unlock();
			}
		}
	}
}

部分输出示例如下:

......

......

Withdraw Released Lock

Withdraw Obtained Lock

Wait for deposit

Deposit Obtained Lock

Deposit 9 13

Deposit Released Lock

Withdraw 9 4

Withdraw Released Lock

.....

.....

这里的问题是为什么存款线程在窗口线程之后获得了锁。按理说,一旦锁被获得,其他线程就不能再获得它,对吗?或者是因为 signal 方法的原因?有人能解释一下这个输出是怎么来的吗?提前谢谢 Java多线程锁定未能正确工作

英文:

The whole program is :

import java.util.concurrent.*;
import java.util.concurrent.locks.*;
public class AccountWithConditionsUser {
private static Account account = new Account();
public static void main(String[] args) {
System.out.println(&quot;Thread 1\t\tThread 2\t\tBalance&quot;);
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new DepositTask());
executor.execute(new WithdrawTask());
executor.shutdown();
while(!executor.isShutdown()) {
}
}
public static class DepositTask implements Runnable{
public void run() {
try {
while(true) {
account.deposit((int)(Math.random()* 10)+ 1);
Thread.sleep(1000);
}
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
public static class WithdrawTask implements Runnable{
public void run() {
while(true) {
account.withdraw((int)(Math.random() * 10) + 1);
}
}
}
private static class Account{
private static Lock lock = new ReentrantLock(true);
private static Condition newDeposit = lock.newCondition();
private int balance = 0;
public int getBalance() {
return balance;
}
public void withdraw(int amount) {
lock.lock();
System.out.println(&quot;-&gt;Withdraw Obtained Lock&quot;);
try {
while(balance &lt; amount) {
System.out.println(&quot;\t\t\tWait for deposit&quot;);
newDeposit.await();
}
balance-=amount;
System.out.println(&quot;\t\t\tWithdraw &quot;+ amount + &quot;\t\t&quot; + getBalance());
}
catch(Exception e) {
e.printStackTrace();
}
finally {
System.out.println(&quot;-&gt;Withdraw Released Lock&quot;);
lock.unlock();
}
}
public void deposit(int amount) {
lock.lock();
System.out.println(&quot;-&gt;Deposit Obtained Lock&quot;);
try {
balance+=amount;
System.out.println(&quot;Deposit &quot;+ amount + &quot;\t\t\t\t\t&quot; + getBalance());
newDeposit.signalAll();
}
catch(Exception e) {
e.printStackTrace();
}
finally {
System.out.println(&quot;-&gt;Deposit Released Lock&quot;);
lock.unlock();
}
}
}
}

And the sample part of the output I got for this code is:

......

......

Withdraw Released Lock

Withdraw Obtained Lock

Wait for deposit

Deposit Obtained Lock

Deposit 9 13

Deposit Released Lock

Withdraw 9 4

Withdraw Released Lock

.....

.....

The question here is how Deposit thread obtained lock after window obtained lock. Isn't it supposed to be that once a lock is obtained it can't be obtained by any other thread! Or is it because of the signal methods? Can anyone please explain how that output came?
Thanks in advance Java多线程锁定未能正确工作

答案1

得分: 0

在获取锁之后,Withdraw 函数会检查是否有足够的余额。如果没有足够的余额,则会调用 newdeposit.await,这将释放锁,以便等待相同锁的其他线程可以进入。这似乎就是发生的情况:Withdraw 进入了该 if 代码块,开始等待,然后 Deposit 线程进来存入一定金额并唤醒了 Withdraw,以便它可以继续使用更新后的金额。一旦收到通知,await 会释放锁并返回,因此 Withdraw 在获得锁的情况下继续执行。

英文:

After Withdraw obtains the lock it checks if there is sufficient balance. If there is not, then it calls newdeposit.await, which will release the lock so other threads waiting on the same lock can get in. That appears to be what happened: Withdraw entered into that if-block, started waiting, the Deposit thread came in and deposited an amount and woke Withdraw up, so it can continue with the updated amount. Once a notification is received, await locks and returns, so Withdraw continues execution with lock acquired.

huangapple
  • 本文由 发表于 2020年8月17日 22:18:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/63452766.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定