У меня есть Java-приложение, которое, помимо прочего, выходит на наш сервер Active Directory каждый час, собирает список всех учетных записей и выгружает их в базу данных; эта работа выполняется через поток, который порождает новый каждый час, а взаимодействие с базой данных осуществляется через Hibernate. Метод запуска потока (по сути, единственное, что делает этот поток) выглядит так:
public void run() {
try {
Thread.sleep(3600000); //we run once an hour, so we sleep for an hour
Thread newHourlyRunThread = new Thread(new HourlyRunThread());
newHourlyRunThread.start();
LDAPNewUsersReport report = new LDAPNewUsersReport();
Calendar calendar = Calendar.getInstance();
calendar.set(0, 0, 0, 0, 0); //We tell the report to look for everything from 12AM Jan 1 0 AD, which should be sufficient to find all created AD objects.
report.runReport(calendar.getTime(), new Date());
HashSet<LDAPEntry> allEntries = report.getAllEntries();
Iterator it = allEntries.iterator();
while (it.hasNext()) {
ContactParser.parseContact((LDAPEntry) it.next());
}
}
Ниже приведены соответствующие методы ContactParser:
public static void parseContact(LDAPEntry entry) {
Contact chosenContact = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List contacts = session.getNamedQuery("ContactByCanonicalName").setString(0, entry.getDN()).list();
Iterator it = contacts.iterator();
if (it.hasNext()) {
chosenContact = (Contact) it.next();
chosenContact = ContactParser.fillContactFields(chosenContact, entry);
} else {
chosenContact = ContactParser.fillContactFields(new Contact(), entry);
}
session.saveOrUpdate(chosenContact);
session.getTransaction().commit();
}
private static Contact fillContactFields(Contact chosenContact, LDAPEntry entry) {
chosenContact.setCanonicalName(entry.getDN());
chosenContact.setFirstName(ContactParser.getEntryField(entry, "givenName"));
chosenContact.setLastName(ContactParser.getEntryField(entry, "sn"));
chosenContact.setUserName(ContactParser.getEntryField(entry, "sAMAccountname"));
chosenContact.setEmployeeID(ContactParser.getEntryField(entry, "employeeID"));
chosenContact.setMiddleName(ContactParser.getEntryField(entry, "initials"));
chosenContact.setEmail(ContactParser.getEntryField(entry, "mail"));
if(chosenContact.getFirstSeen() == null){
chosenContact.setFirstSeen(new Date());
}
chosenContact.setLastSeen(new Date());
return chosenContact;
}
private static String getEntryField(LDAPEntry entry, String fieldName){
String returnString = "";
if(entry.getAttribute(fieldName) != null){
returnString = entry.getAttribute(fieldName).getStringValue();
}
return returnString;
}
Это все работает очень хорошо, если мы запускаем только один экземпляр (поэтому новые потоки не создаются по факту), но если мы запускаем этот поток более одного раза (IE, я ускоряю выполнение до ~ 30 секунд чтобы я мог видеть проблемы), Hibernate сообщает об отсутствии места в куче. Похоже, это не слишком интенсивный набор данных (всего около 6 тыс. Записей), но я вижу ту же ошибку, когда мы помещаем код в промежуточную ошибку, чтобы подготовиться к запуску в производство. Я неопытен, когда дело доходит до написания эффективных потоков, и очень неопытен, когда дело доходит до Hibernate, поэтому, если у кого-то есть идея, что может исчерпать наше пространство кучи (другой основной поток в этом приложении не работает одновременно и, глядя на код, занимает несколько сотен килобайт памяти), я был бы очень признателен за любые предложения.
Заранее спасибо.