Mehrere Threads und eine Liste

DosCoder

Erfahrenes Mitglied
Hi Leute,
ich habe mir eine Klasse geschrieben, die von Hashmap erbt.
Die Methode addNewEintrag soll einen Eintrag in die Liste schreiben und nach
long time wieder löschen:
Java:
public class DeleteHashMap<K,T> extends Hashmap{

   public void addNewEintrag(long time, T eintrag, K key){
       put(key,eintrag);
       Runnable job = new Runnable(){
            @Override public void run(){
                  try{
                       Thread.sleep(time);
                        remove(eintrag)
                  }catch(InterrupptedException e){}
             }
         }
     }
}
Allerdings wird jetzt eine Exception geworfen(der Name ist mir entfallen), in deren Beschreibung steht, dass sie geworfen wird, wenn mehrere Threads auf ein und die selbe Liste zugreifen. Dass das Probleme bereitet ist mir klar.

Also weiß jemand vielleicht eine Alternative, sodass ich Einträge aus einer Hashmap nach einer bestimmten Zeit wieder gelöscht werden, und die Liste aber weiterhin von außen gelesen werden kann und ich mehrere Einträge zur gleichen Zeit haben kann?. Ich beiße mir jetzt schon seit 2 Tagen an diesem Problem die Zähne aus, aber ich komme einfach nicht weiter.

Würde mich sehr freuen!

Ciao
DosCoder
 
Du musst wahrscheinlich den remove Teil synchronisieren, so dass während removed wird kein anderer Thread in der HashMap etwas ändert. Wodurch die ConcurentModificationException fliegt.
 
Hallo,

schau mal hier:
Java:
package de.tutorials.training;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TimeOutAwareConcurrentMapExample {
	public static void main(String[] args) throws Exception {
		TimeOutAwareConcurrentMap<String, String> map = new TimeOutAwareConcurrentMap<String, String>();

		map.put("a", "aaa");
		map.put("b", "bbb");
		map.put("c", "ccc");

		map.put("d", "ddd", 10, TimeUnit.SECONDS);
		map.put("e", "eee", 3, TimeUnit.SECONDS);

		for (int i = 0; i < 12; i++) {
			System.out.println(map);
			TimeUnit.SECONDS.sleep(1);
		}

		map.setTimeOutCheckingStopped(true);
	}

	public static class TimeOutAwareConcurrentMap<TKey, TValue> extends
			ConcurrentHashMap<TKey, TValue> {
		private final Lock lock = new ReentrantLock();
		private final ConcurrentMap<TKey, TimeOutInfo> keysWithTimeOut = new ConcurrentHashMap<TKey, TimeOutInfo>();
		private volatile int checkForTimeOutPeriodInMillis = 1000;
		private volatile boolean timeOutCheckingEnabled = true;
		private volatile boolean timeOutCheckingStopped = false;

		public int getCheckForTimeOutPeriodInMillis() {
			return checkForTimeOutPeriodInMillis;
		}

		public void setCheckForTimeOutPeriodInMillis(
				int checkForTimeOutPeriodInMillis) {
			this.checkForTimeOutPeriodInMillis = checkForTimeOutPeriodInMillis;
		}

		public boolean isTimeOutCheckingEnabled() {
			return timeOutCheckingEnabled;
		}

		public void setTimeOutCheckingEnabled(boolean timeOutCheckingEnabled) {
			this.timeOutCheckingEnabled = timeOutCheckingEnabled;
		}

		public boolean isTimeOutCheckingStopped() {
			return timeOutCheckingStopped;
		}

		public void setTimeOutCheckingStopped(boolean timeOutCheckingStopped) {
			this.timeOutCheckingStopped = timeOutCheckingStopped;
		}

		public boolean hasTimeOut(TKey key) {
			return this.keysWithTimeOut.containsKey(key);
		}

		public TimeOutInfo getTimeOutInfo(TKey key) {
			return this.keysWithTimeOut.get(key);
		}

		public TimeOutAwareConcurrentMap() {
			// Executors.newSingleThreadExecutor().execute(createTimeOutedKeyBouncer());
			final Thread thread = new Thread(createTimeOutedKeyBouncer(), generateCheckerThreadName());
			thread.setDaemon(true);
			thread.start();
		}

		protected String generateCheckerThreadName() {
			return TimeOutAwareConcurrentMap.class + "-" + System.identityHashCode(this) + " time-out checker";
		}

		protected Runnable createTimeOutedKeyBouncer() {
			return new Runnable() {
				@Override
				public void run() {

					while (!isTimeOutCheckingStopped()) {

						if (isTimeOutCheckingEnabled() && keysWithTimeOut.size() > 0) {
							checkForKeysWithTimeOut();
						}

						try {
							TimeUnit.MILLISECONDS.sleep(getCheckForTimeOutPeriodInMillis());
						} catch (InterruptedException ie) {
							Thread.currentThread().interrupt();
						}

					}

					purgeTimeOutAwareKeysFromTracking();
				}
			};
		}

		protected void checkForKeysWithTimeOut() {
			for (Map.Entry<TKey, TimeOutInfo> entry : new HashMap<TKey, TimeOutInfo>(this.keysWithTimeOut).entrySet()) {
				if (entry.getValue().isTimedOut()) {
					try {
						lock.lock();
						timeout(entry.getKey());
						this.keysWithTimeOut.remove(entry.getKey());
					} finally {
						lock.unlock();
					}
				}
			}
		}

		protected void timeout(TKey key) {
			System.out.println("Timeout for: " + key);
			remove(key);
		}

		protected void purgeTimeOutAwareKeysFromTracking() {
			this.keysWithTimeOut.clear();
		}

		@Override
		public void clear() {
			super.clear();
			purgeTimeOutAwareKeysFromTracking();
		}

		public void put(TKey key, TValue value, long amountInUnits,
				TimeUnit unit) {
			if (key == null)
				throw new UnsupportedOperationException("null keys are not supported");
			try {
				lock.lock();
				put(key, value);
				this.keysWithTimeOut.put(key, new TimeOutInfo(unit.toMillis(amountInUnits)));
			} finally {
				lock.unlock();
			}
		}

		@Override
		public TValue put(TKey key, TValue value) {
			return super.put(key, value);
		}

		@Override
		public TValue remove(Object key) {
			try {
				lock.lock();
				this.keysWithTimeOut.remove(key);
				return super.remove(key);
			} finally {
				lock.unlock();
			}
		}


		public static class TimeOutInfo {
			final long timeoutInMillis;
			final long startTimeStampInMillis;

			public TimeOutInfo(long timeoutInMillis) {
				this.timeoutInMillis = timeoutInMillis;
				this.startTimeStampInMillis = System.currentTimeMillis();
			}

			public long getTimeoutInMillis() {
				return timeoutInMillis;
			}

			public long getCurrentTimeMillisAtStart() {
				return startTimeStampInMillis;
			}

			public boolean isTimedOut() {
				boolean timeout = (System.currentTimeMillis() - this.startTimeStampInMillis) >= timeoutInMillis;
				return timeout;
			}
		}
	}
}

Ausgabe:
Code:
{a=aaa, b=bbb, e=eee, c=ccc, d=ddd}
{a=aaa, b=bbb, e=eee, c=ccc, d=ddd}
{a=aaa, b=bbb, e=eee, c=ccc, d=ddd}
{a=aaa, b=bbb, e=eee, c=ccc, d=ddd}
Timeout for: e
{a=aaa, b=bbb, c=ccc, d=ddd}
{a=aaa, b=bbb, c=ccc, d=ddd}
{a=aaa, b=bbb, c=ccc, d=ddd}
{a=aaa, b=bbb, c=ccc, d=ddd}
{a=aaa, b=bbb, c=ccc, d=ddd}
{a=aaa, b=bbb, c=ccc, d=ddd}
{a=aaa, b=bbb, c=ccc, d=ddd}
Timeout for: d
{a=aaa, b=bbb, c=ccc}

Gruß Tom
 
Zurück