消息驱动Bean中的并发性 - 线程安全Java EE5与EE6

时间:2016-04-18 08:05:21

标签: multithreading thread-safety ejb message-driven-bean synchronize

我遇到一种情况,我需要将一组操作包含在单个事务中,并且是MDB的线程安全。

如果线程A执行指令1,则不希望其他线程可以读取线程A正在处理的数据,至少不一样。 在下面的代码中,因为IMAGE表包含来自不同来源的重复数据,这将导致重复的INFRANCTION。需要避免的情况。

我找到的实际解决方案是为每个新邮件声明一个新事务并同步整个事务。 简化代码:

@Stateless
InfranctionBean{
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    checkInfranction(String plate){
        1. imageBean.getImage(plate); // read from table IMAGE
        2. infranctionBean.insertInfranction(String plate); // insert into table INFRANCTION
        3. imageBean.deleteImage(String plate); //delete from table IMAGE
    }
}

@MessageDriven
public class ImageReceiver {

    private static Object lock = new Object();

    public void onMessage(Message msg){
        String plate = msg.plate;

        synchronized (lock) {
            infanctionBean.checkInfranction(plate);
        }
    }
}

我知道EJB规范并不建议在EJB中使用synchronized块。如果应用服务器在两个节点集群中运行,这甚至会导致问题。

似乎EE6已经为这种情况引入了一个解决方案,即EJB Singleton。 在这种情况下,我的解决方案将是这样的:

@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@Singleton
InfranctionBean{

    @Lock(LockType.WRITE)
    checkInfranction(String plate){
        1...
        2...
        3...
    }
}

并且从MDB开始不需要使用synchronized块,因为容器将处理并发。 使用@Lock(WRITE),容器保证在checkInfranction()中访问单个线程。

我的问题是:我如何处理EE5中的这种情况?有没有使用synchronized块的清洁解决方案?

环境:Java5,jboss-4.2.3.GA,Oracle10。

实际解决方案

@Stateless
InfranctionBean{
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    checkInfranction(String plate){    
        1. imageBean.lockImageTable(); // lock table IMAGE in exclusive mode
        2. imageBean.getImage(plate); // read from table IMAGE
        3. infranctionBean.insertInfranction(String plate); // insert into table INFRANCTION
        4. imageBean.deleteImage(String plate); //delete from table IMAGE
    }
}

@MessageDriven
public class ImageReceiver {
    public void onMessage(Message msg){
        infanctionBean.checkInfranction(msg.plate);
    }
}

在20.000个传入消息(其中一半同时)似乎应用程序正常工作。

1 个答案:

答案 0 :(得分:2)

# plot projection of density onto z-axis plotdat = np.sum(density, axis=2) plotdat = plotdat / np.max(plotdat) plotx, ploty = np.mgrid[-4:4:100j, -4:4:100j] ax.contour(plotx, ploty, plotdat, offset=-4, zdir='z') #This is new #plot projection of density onto y-axis plotdat = np.sum(density, axis=1) #summing up density along y-axis plotdat = plotdat / np.max(plotdat) plotx, plotz = np.mgrid[-4:4:100j, -4:4:100j] ax.contour(plotx, plotdat, plotz, offset=4, zdir='y') #plot projection of density onto x-axis plotdat = np.sum(density, axis=0) #summing up density along z-axis plotdat = plotdat / np.max(plotdat) ploty, plotz = np.mgrid[-4:4:100j, -4:4:100j] ax.contour(plotdat, ploty, plotz, offset=-4, zdir='x') #continue with your code 只是单个应用程序/ JVM中的锁,因此除非您能保证只有一个应用程序/ JVM正在访问数据,否则您无法获得太多保护。如果您只是在寻找单一应用程序/ JVM保护,那么EE 5中的最佳解决方案将是ReadWriteLock或同步块。 (EJB规范具有阻止应用程序执行此操作以避免破坏服务器的线程管理的语言,因此请注意不要无限期地阻塞,不要忽略中断等。)

如果您正在寻找更强大的跨应用程序/ JVM解决方案,我会使用数据库锁或隔离级别,而不是尝试依赖JVM同步原语。无论使用何种EJB版本,这都可能是最佳解决方案。