简单模拟多线程访问同样变量导致的问题,需要使用Transaction控制,或加锁。
修正其中的问题方法一:把其中的方法作为一个Transaction
其中只增加了一个关键字: synchronized 同步方法非常简单,这样方法就作为了原子来执行。
但是,如果只有这个方法访问account,那么不会出现问题,如果还有方法需要访问account,那么需要使用Object key 才有效了,否则即便这个方法封锁了自己,仍然可能获得错误的account而执行错误的操作。
如下的例子导致了“Lost Update”
在执行过程中是很有出错概率的。解决方法还是一样的:在该increaseBalance()上加上synchronized关键字。
出现的适用范围也是一样,只有歌操作balance的的方法是有效的,但是如果还有其它线程用不同方法操作balance就会遇到问题。
package
practice;
public class RyanAndMonicaJob implements Runnable {
private BankAccount account = new BankAccount();
public static void main(String[] args){
RyanAndMonicaJob runner = new RyanAndMonicaJob();
Thread one = new Thread(runner);
Thread two = new Thread(runner);
one.setName("Ryan");
two.setName("Monica");
one.start();
two.start();
}
public void run(){
for(int i=0; i< 10; i++){
withdraw(30);
}
if(account.getBalance()<0){
System.out.println("the account is overdrawed!");
}
}
private void withdraw(int amount){
if(account.getBalance()>amount){
try{
System.out.println(Thread.currentThread().getName() +" is going to sleep.");
Thread.sleep(500);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " woke up");
account.withdraw(amount);
System.out.println("after " + Thread.currentThread().getName() + " withdraw, the account is: " + account.getBalance());
}else{
System.out.println("sorry " + Thread.currentThread().getName() + " the money is : " + account.getBalance());
}
}
}
public class RyanAndMonicaJob implements Runnable {
private BankAccount account = new BankAccount();
public static void main(String[] args){
RyanAndMonicaJob runner = new RyanAndMonicaJob();
Thread one = new Thread(runner);
Thread two = new Thread(runner);
one.setName("Ryan");
two.setName("Monica");
one.start();
two.start();
}
public void run(){
for(int i=0; i< 10; i++){
withdraw(30);
}
if(account.getBalance()<0){
System.out.println("the account is overdrawed!");
}
}
private void withdraw(int amount){
if(account.getBalance()>amount){
try{
System.out.println(Thread.currentThread().getName() +" is going to sleep.");
Thread.sleep(500);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " woke up");
account.withdraw(amount);
System.out.println("after " + Thread.currentThread().getName() + " withdraw, the account is: " + account.getBalance());
}else{
System.out.println("sorry " + Thread.currentThread().getName() + " the money is : " + account.getBalance());
}
}
}
package
practice;
public class BankAccount {
int balance = 200;
public int getBalance(){
return balance;
}
public void withdraw(){
balance = balance - 150;
}
}
public class BankAccount {
int balance = 200;
public int getBalance(){
return balance;
}
public void withdraw(){
balance = balance - 150;
}
}
修正其中的问题方法一:把其中的方法作为一个Transaction
package
practice;
public class RyanAndMonicaJob implements Runnable {
private BankAccount account = new BankAccount();
public static void main(String[] args){
RyanAndMonicaJob runner = new RyanAndMonicaJob();
Thread one = new Thread(runner);
Thread two = new Thread(runner);
one.setName("Ryan");
two.setName("Monica");
one.start();
two.start();
}
public void run(){
for(int i=0; i< 10; i++){
withdraw(30);
}
if(account.getBalance()<0){
System.out.println("the account is overdrawed!");
}
}
private synchronized void withdraw(int amount){
if(account.getBalance()>amount){
try{
System.out.println(Thread.currentThread().getName() +" is going to sleep.");
Thread.sleep(500);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " woke up");
account.withdraw(amount);
System.out.println("after " + Thread.currentThread().getName() + " withdraw, the account is: " + account.getBalance());
}else{
System.out.println("sorry " + Thread.currentThread().getName() + " the money is : " + account.getBalance());
}
}
}
public class RyanAndMonicaJob implements Runnable {
private BankAccount account = new BankAccount();
public static void main(String[] args){
RyanAndMonicaJob runner = new RyanAndMonicaJob();
Thread one = new Thread(runner);
Thread two = new Thread(runner);
one.setName("Ryan");
two.setName("Monica");
one.start();
two.start();
}
public void run(){
for(int i=0; i< 10; i++){
withdraw(30);
}
if(account.getBalance()<0){
System.out.println("the account is overdrawed!");
}
}
private synchronized void withdraw(int amount){
if(account.getBalance()>amount){
try{
System.out.println(Thread.currentThread().getName() +" is going to sleep.");
Thread.sleep(500);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " woke up");
account.withdraw(amount);
System.out.println("after " + Thread.currentThread().getName() + " withdraw, the account is: " + account.getBalance());
}else{
System.out.println("sorry " + Thread.currentThread().getName() + " the money is : " + account.getBalance());
}
}
}
其中只增加了一个关键字: synchronized 同步方法非常简单,这样方法就作为了原子来执行。
但是,如果只有这个方法访问account,那么不会出现问题,如果还有方法需要访问account,那么需要使用Object key 才有效了,否则即便这个方法封锁了自己,仍然可能获得错误的account而执行错误的操作。
如下的例子导致了“Lost Update”
package
practice;
public class TestSync implements Runnable {
private int balance;
public void run(){
for(int i=0;i<5000;i++){
increaseBalance();
}
}
private void increaseBalance(){
System.out.println(Thread.currentThread().getName() + ++balance);
}
}
public class TestSync implements Runnable {
private int balance;
public void run(){
for(int i=0;i<5000;i++){
increaseBalance();
}
}
private void increaseBalance(){
System.out.println(Thread.currentThread().getName() + ++balance);
}
}
package
practice;
public class TestSyncTest {
public static void main(String[] args){
TestSync runner = new TestSync();
Thread one = new Thread(runner);
Thread two = new Thread(runner);
one.setName("A");
two.setName("B");
one.start();
two.start();
}
}
public class TestSyncTest {
public static void main(String[] args){
TestSync runner = new TestSync();
Thread one = new Thread(runner);
Thread two = new Thread(runner);
one.setName("A");
two.setName("B");
one.start();
two.start();
}
}
在执行过程中是很有出错概率的。解决方法还是一样的:在该increaseBalance()上加上synchronized关键字。
出现的适用范围也是一样,只有歌操作balance的的方法是有效的,但是如果还有其它线程用不同方法操作balance就会遇到问题。