繁体   English   中英

如何使方法线程安全,即使我忘记在方法或块级别添加同步而不更改文件?

[英]How to make method thread safe, even I forget to add synchronization on method or block level without changing file?

在一位知名公司的面试中,我收到了如下问题:

你有一个类,你的同事忘记同步一些重要的方法,你如何在不改变同一个类的情况下使它线程安全?

public class Account{

    //some variables

    public boolean withdraw()
    {
        //some business logic
        return true;
    }

    public boolean deposite()
    {
        //some business logic
        return false;
    }
}

我不确定答案是什么,这也可能是愚蠢的答案。 请帮我得到答案。

我的回答:我给出的答案就像我们可以对其进行包装并且我们可以同步。 这不是令人信服的答案,我认为这是获得答案的最佳平台

我在这里看到两个可能的答案:

  1. 扩展Acount类并同步方法访问:
public class SyncrhonizedAccess extends Account {
   public synchronized boolean withdraw() {
     return super.withdraw();
   }

   public synchronized boolean deposite() {
      return super.deposite();
   }
}
  1. 包装类并同步对包装对象的访问:
public class AccountWrapper {
    private final Account realAcount;

    public AccountWrapper(Account realAccount) {
       this.realAccount = realAccount;
    }

    public synchronized boolean withdraw()
    {
       return realAccount.withdraw();
    }

    public synchronized boolean deposite()
    {
        return realAccount.deposite();
    }
}

现在这两种方法都可以通过多种方式完成(像我展示的那样手动),自动生成(归结为上述方法之一,只是由像 CGLIB(字节代码生成库)这样的库“自动”完成),或者甚至使用 AOP(面向方面​​的编程)。

另一个注意事项是,可以在方法内部创建一个锁并对其进行同步,而不是使用单词synchronized

当然,如果Account类具有共享状态,那么这一切都是有意义的 - 数据字段实际上被withdrawdeposite方法更改和访问。 否则你真的不需要同步任何东西。

我肯定会使用一个方面并同步对方法的调用。 我会选择这个选项,因为我的应用程序或第三方库的其他点正在调用这些方法

代码示例:

@Aspect
public class AspectAccount {

    private static final Object lock = new Object();

    @Pointcut("execution(* path.to.package.Account.*(..) )")
    public void callAt() {
    }

    @Around("callAt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        synchronized (lock) {
            return pjp.proceed();
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM