java thread synchronization demonstration

Thread synchronization

1. Questions:

Simulation of withdrawal of the same bank account at multiple locations at the same time

The specific code is as follows:

account class:

package thread;

public class Account 
{
    //An account name and a balance
	private String acNo;
	private int balance;
	Account(String ac,int bal)
	{
		acNo=ac;
		balance=bal;
	}
    //set method and get method
	public void setAccountNo(String no)
	{
		acNo=no;
	}
	public void setBalance(int bal)
	{
		balance=bal;
	}
	public String getAccoutNo()
	{
		return acNo;
	}
	public int getBalance()
	{
		return balance;
	}
    //Two methods of using Overlay
	@Override
	public int hashCode() {
		return acNo.hashCode();
	}
	@Override
	public boolean equals(Object obj) {
		if(obj==this)
			return true;
		if(obj!=null&&obj.getClass()==Account.class)
		{
			Account target=(Account)obj;
			return target.equals(acNo);
		}
		return false;
	}
}

Withdrawal category:

package thread;

public class DrawAccount extends Thread
{
	//	User's account
	private Account acn;
	private double drawMoney;
	public DrawAccount(String name,Account ac,double reduce)
	{
		super(name);
		acn=ac;
		drawMoney=reduce;
	}
	public void run()
	{
		if(acn.getBalance()>drawMoney)
		{
			//Take out the banknote
			System.out.println(this.getName()+" The money was withdrawn successfully: "+drawMoney);
			//Increase error rate
			/*try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
			
				e.printStackTrace();
			}*/
			//Minus notes
			acn.setBalance((int) (acn.getBalance()-drawMoney));
			//Print balance
			System.out.println("The balance is: "+acn.getBalance());
		}
		else {
			System.out.println("Withdrawal failed, the balance is "+acn.getBalance());
		}
		
	}
}

ps: it is worth noting that the annotated code can increase the error rate

Test class:

package thread;

public class DrawTest 
{
	public static void main(String[]__)
	{
		Account he=new Account("123", 1600);
		new DrawAccount("Withdrawal machine 1", he, 1000).start();

		new DrawAccount("Withdrawal machine 2", he, 1000).start();
	}
}

After multiple runs, you will see the following:

Let's explain a little here:

  • If we have known about thread synchronization before, we should be clear about these two concepts: atomicity and visibility. For the money withdrawal operation here, the two actions of judgment and fee deduction are not atomic operations. Therefore, when one thread has been judged to be successful, the CPU usage right is seized by another thread for judgment. At this time, the account has not been deducted, Therefore, the account balance is negative.

2. Synchronous approach

‚Äč In order to solve the above problems, java multithreading uses the synchronization monitor. The syntax format of the synchronization code block is as follows:

synchronized(obj)
{
    //Code block
}

obj in parentheses is the synchronization monitor. The meaning of the above code is that the synchronization monitor must be locked before the thread starts executing. Any thread must obtain the lock before running the synchronization code block. Process: "lock" - > "modify lock" - > "release lock"

The obj lock generally uses shared variables as the lock. When the program runs to synchronize, it will first judge whether the obj lock has been obtained by others.

There are also synchronization methods

public synchronized void run
{
    //Code block
}

This time is equivalent to using this as obj to act as a lock

Thread safety of variable classes is achieved by reducing efficiency. In order to reduce negative effects:

  • Instead of synchronizing all resources, you only need to lock competing resources (shared resources)
  • Variable classes have two running environments: single thread and multi thread. Two versions of variable classes should be provided, single thread efficiency and multi thread safety.

3. Release of lock

The lock is released in the following cases:

  • The synchronization method of the current thread. The execution of the synchronization code block ends, and the current thread releases the lock
  • When a break is encountered, the return statement releases the lock
  • When an unhandled ERROR and EXCEPTION are encountered, the lock will be released
  • When the thread executes the synchronization code block, the program executes the wait() method of the synchronization monitor object, the current thread pauses and releases the synchronization monitor (ps:wait() method inherits the object class)

The following situations will not release the lock and may cause deadlock:

  • The program calls the sleep() method and the yield() method without releasing the lock
  • The thread calls the suspend() method of the thread to suspend the thread, and the thread will not release the synchronization monitor

Complements yesterday forgot the join () method: blocking the thread of the calling thread, waiting for the thread to be executed after the execution of the thread being executed, then the thread of the calling thread will continue to execute, and the wait() method is used at the bottom.

Posted by CaptianChaos on Sat, 06 Nov 2021 04:56:45 -0700