我试图了解 ExecutorService 以及它将如何避免使用同步关键字。我尝试了下面类似的操作(为了清楚起见,避免导入),但给出了错误的结果:
public class ReadWebPage
{
public static void main(String[] args)
{
ExecutorService executor = Executors.newFixedThreadPool(5);
FinTrans ft = new FinTrans ();
TransThread tt1 = new TransThread (ft, "Deposit Thread");
TransThread tt2 = new TransThread (ft, "Withdrawal Thread");
executor.submit(tt2);
executor.submit(tt1);
executor.shutdown();
}
}
class FinTrans
{
public static String transName;
public static double amount;
}
class TransThread implements Runnable
{
private FinTrans ft;
private String name;
TransThread (FinTrans ft, String name)
{
this.name = name;
this.ft = ft;
}
public String getName(){
return name;
}
public void run ()
{
for (int i = 0 ; i < 10 ; i++ )
{
if (getName ().equals ("Deposit Thread"))
{
ft.transName = "Deposit";
try
{
Thread.sleep ((int) (Math.random () * 100));
}
catch (InterruptedException e)
{
}
ft.amount = 2000.0;
System.out.println (ft.transName + " " + ft.amount);
}
else
{
ft.transName = "Withdrawal";
try
{
Thread.sleep ((int) (Math.random () * 10));
}
catch (InterruptedException e)
{
}
ft.amount = 250.0;
System.out.println (ft.transName + " " + ft.amount);
}
}
}
}
这给了我错误的结果:
Deposit 250.0 //wrong
Withdrawal 250.0
Withdrawal 250.0
Withdrawal 250.0
Withdrawal 250.0
Withdrawal 250.0
Withdrawal 250.0
Withdrawal 250.0
Withdrawal 250.0
Withdrawal 2000.0 //wrong
Deposit 250.0 //wrong
Deposit 2000.0
Deposit 2000.0
Deposit 2000.0
Deposit 2000.0
Deposit 2000.0
Deposit 2000.0
Deposit 2000.0
Deposit 2000.0
Deposit 2000.0
您能解释一下这里出了什么问题吗? 1. 是因为两个 Runnable 共享同一个 FinTrans 对象吗? 2. 这是否意味着我们也需要同样的旧同步机制?
我试图了解在什么情况下我们可以使用ServiceExecutors
阿南德
最佳答案
ExecutorService 并行运行作业,但不会自动确保跨线程并发访问共享状态的安全性。所以,你的问题的两个部分都是"is"。
- 该问题的部分原因是两个可运行对象共享相同的
FinTrans
状态对象。 - 问题的另一部分是缺乏对共享状态的访问的任何同步或其他原子保证。
执行器非常适合异步提交任务,并能够通过返回的 Future
实例检查其状态(例如,它们是否已完成)。
关于Java ExecutorService 和同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27519301/