# Wie parent stack trace im Thread ausgeben



## DerMartin007 (7. August 2007)

Hallo,

ich habe ein Problem beim loggen des Stacktraces aus einem Subthread heraus. 
Ich habe eine Thread Group welche mehrere Threads ausführt. Diese Threads starten nun weitere subthreads in jeweils einer neuen Thread Group und warten dann über das Future Object auf einne Rückgabewert.
Das Exception Handling möchte ich im Thread belassen um es hier Zentral für die Methode abzuhandeln und so auch einen entsprechenden Rückgabewert zurück geben möchte.

Jedoch habe ich nun das Problem das im Falle einer Exception der Stacktrace des Parent Threads für mich interessant ist und nicht der Stacktrace des subthreads. Da die Subthreads mehfrach verwendet werden und ich dann weiß an welcher Stelle genau etwas schief gegangen ist.

Wie kann ich nun aus dem Subthread heraus den Stacktrace des Parentthreads ausgeben ?

Vielleicht kann mir hier ja jemand weiter helfen.
Vielen Dank.


----------



## schnuffie (8. August 2007)

```
Thread parentThread = new Thread("heinz");
 
// hier kommen Deine verschiedenen ThreadGroup-Verschachtelungen
```
 
Abfrage des Stacktrace:

```
Map map<Thread, StackTraceElement[]> = Thread.getAllStackTraces();
StackTraceElement[] element = map.get(parentThread);
 
// nun ausgeben
```


----------



## Thomas Darimont (8. August 2007)

Hallo,

du kannst in Java nicht wirklich rausfinden, aus welchem Thread genau ein anderer Thread hervorgegenagen ist. Wird ein Thread gestartet so ist dieser in der selben ThreadGroup wie der Thread aus dem er hervorgegangen ist (sofern nicht explizit eine andere ThreadGroup angegeben wurde). Darüber "könnte" man dann zumindest die Threads eingrenzen die als ersteller in Frage kommen, jedoch bekommt man so nicht genau den Thread heraus ... es sei denn man startet jeden (starter) Thread in einer eigenen ThreadGroup...

Wenn du die Information zum Erzeuger Thread brauchst würd ich mir die mitspeichern:

```
/**
 * 
 */
package de.tutorials;

import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;

/**
 * @author Thomas.Darimont
 * 
 */
public class CreationAwareThreadExample {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		startAnotherThread(666);

		new Thread("Starter") {
			@Override
			public void run() {
				for (int i = 0; i < 3; i++) {

					startAnotherThread(i);

				}
			}
		}.start();
	}

	protected static void startAnotherThread(final int i) {
		new CreationAwareThread("Thread: " + i) {
			@Override
			public void run() {
				System.out.println(getName() + " was started by: "
						+ buildCreationThreadInfoText());
				try {
					TimeUnit.SECONDS.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				System.out.println("Exiting: " + getName());
			}

			private String buildCreationThreadInfoText() {
				StringBuilder stringBuilder = new StringBuilder(
						getCreatorThreadName());
				stringBuilder.append(": @");
				for (StackTraceElement stackTraceElement : getStartTimeStackTraceOfCreatorThread()) {
					stringBuilder.append(stackTraceElement);
					stringBuilder.append("\n");
				}
				return stringBuilder.toString();
			}
		}.start();
	}

	static class CreationAwareThread extends Thread {
		WeakReference<Thread> creatorThread;
		String creatorThreadName;
		StackTraceElement[] startTimeStackTraceOfCreatorThread;

		public CreationAwareThread(String name) {
			super(name);
		}

		@Override
		public synchronized void start() {
			this.creatorThread = new WeakReference<Thread>(Thread
					.currentThread());
			this.creatorThreadName = Thread.currentThread().getName();
			this.startTimeStackTraceOfCreatorThread = Thread.currentThread()
					.getStackTrace();
			super.start();
		}

		/**
		 * @return the creatorThread
		 */
		public WeakReference<Thread> getCreatorThread() {
			return creatorThread;
		}

		/**
		 * @param creatorThread
		 *            the creatorThread to set
		 */
		public void setCreatorThread(WeakReference<Thread> creatorThread) {
			this.creatorThread = creatorThread;
		}

		/**
		 * @return the creatorThreadName
		 */
		public String getCreatorThreadName() {
			return creatorThreadName;
		}

		/**
		 * @param creatorThreadName
		 *            the creatorThreadName to set
		 */
		public void setCreatorThreadName(String creatorThreadName) {
			this.creatorThreadName = creatorThreadName;
		}

		/**
		 * @return the startTimeStackTraceOfCreatorThread
		 */
		public StackTraceElement[] getStartTimeStackTraceOfCreatorThread() {
			return startTimeStackTraceOfCreatorThread;
		}

		/**
		 * @param startTimeStackTraceOfCreatorThread
		 *            the startTimeStackTraceOfCreatorThread to set
		 */
		public void setStartTimeStackTraceOfCreatorThread(
				StackTraceElement[] startTimeStackTraceOfCreatorThread) {
			this.startTimeStackTraceOfCreatorThread = startTimeStackTraceOfCreatorThread;
		}

	}

}
```

Ausgabe:

```
Thread: 1 was started by: Starter: @java.lang.Thread.getStackTrace(Thread.java:1426)
de.tutorials.CreationAwareThreadExample$CreationAwareThread.start(CreationAwareThreadExample.java:77)
de.tutorials.CreationAwareThreadExample.startAnotherThread(CreationAwareThreadExample.java:59)
de.tutorials.CreationAwareThreadExample$1.run(CreationAwareThreadExample.java:27)

Thread: 666 was started by: main: @java.lang.Thread.getStackTrace(Thread.java:1426)
de.tutorials.CreationAwareThreadExample$CreationAwareThread.start(CreationAwareThreadExample.java:77)
de.tutorials.CreationAwareThreadExample.startAnotherThread(CreationAwareThreadExample.java:59)
de.tutorials.CreationAwareThreadExample.main(CreationAwareThreadExample.java:20)

Thread: 2 was started by: Starter: @java.lang.Thread.getStackTrace(Thread.java:1426)
de.tutorials.CreationAwareThreadExample$CreationAwareThread.start(CreationAwareThreadExample.java:77)
de.tutorials.CreationAwareThreadExample.startAnotherThread(CreationAwareThreadExample.java:59)
de.tutorials.CreationAwareThreadExample$1.run(CreationAwareThreadExample.java:27)

Thread: 0 was started by: Starter: @java.lang.Thread.getStackTrace(Thread.java:1426)
de.tutorials.CreationAwareThreadExample$CreationAwareThread.start(CreationAwareThreadExample.java:77)
de.tutorials.CreationAwareThreadExample.startAnotherThread(CreationAwareThreadExample.java:59)
de.tutorials.CreationAwareThreadExample$1.run(CreationAwareThreadExample.java:27)

Exiting: Thread: 0
Exiting: Thread: 1
Exiting: Thread: 2
Exiting: Thread: 666
```

Bei der ExecutorService Abstraktion kann man bei Executors eine ThreadFactory hinterlegen die genau diese Art von Threads statt der standard Threads erzeugt.

Um dann den StackTrace des Erzeugungsthreads zu haben müsste man sich den auch mitspeichern.

Gruß Tom


----------



## DerMartin007 (9. August 2007)

Vielen Dank für die schnelle Hilfe.

Schnuffie dein Ansatz geht in meinem Fall leider nicht. Da, wie Thomas beschrieben hat, ich den starter Thread nicht genau bestimmen kann. Ich kann nur die ThreadGroup welche die möglichen Starter enthält bestimmen.

Danke Thomas. Genau soetwas hatte ich gebraucht. Den ExecutorService und die ThreadFactory benutze ich schon um meine Threads zu erzeugen. Dann werde ich mal versuchen deinen Ansatz in eine ThreadFactory einzubauen.
Ist zwar nicht so schön sich den StackTrace vom starter Thread immer mit zu merken. Da ich diese Information NUR im Falle einer Exception benötige. Aber anders geht es ja wohl leider nicht. Da ich das Ergebnis des Threads mittels Future Object zurück gebe und das Ergebnis natürlich von einer Exception abhängig ist. Das Exception Handling sollte schon im Thread mit abgehandelt werden.

So, werde mich dann gleich mal an die Arbeit machen.

Gruß
Martin


----------



## Thomas Darimont (9. August 2007)

Hallo,

das Rausschreiben / Merken der Informationen könnte man hier auch über einen AspectJ aspect machen, dann muss man sich das nicht direkt an der eigenen Threadklasse merken.

Gruß Tom


----------



## DerMartin007 (9. August 2007)

Hallo,

ich hatte jetzt mal etwas Zeit um mich mit meinem Problem zu beschäftigen. Leider bin ich was Java angeht noch Neuling 
Wie bekomme ich denn über die ThreadFactory den StackTrace des Erzeugerthreads in meinen SubThread hinein ?

Hier mein Versuch mit der Thread Factory:

```
package common.util.concurrency;

import java.lang.ref.WeakReference;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;


/**
 * Description:	
 * Factory for making threads. Used in ExecutionFramework. 
 * Either creates a new Thread Group or uses a given Thread Group or uses 
 * the Thread Group from the thread calling this factory. 
 * Generates unique name for each created thread. Never creates daemon thread.
 * Priority for newly created threads are same as for thread calling this factory.
 * 
 */
public class CreationAwareThreadFactory implements ThreadFactory {

		private String poolName;
		private ThreadGroup group;
		private AtomicInteger threadNumber = new AtomicInteger(1);
		private String namePrefix;
		
		private Logger logger = Logger.getRootLogger();
		
		
		public CreationAwareThreadFactory( String poolName ) {
			this( poolName, Thread.currentThread().getThreadGroup() );
		}
		
		public CreationAwareThreadFactory( String poolName, String threadGroupName ) {
			this( poolName, new ThreadGroup( threadGroupName ) );
		}
		
		public CreationAwareThreadFactory( String poolName, ThreadGroup group ) {
			logger.debug("ThreadFactory(" + poolName + ")");
			this.poolName = poolName;
			
			SecurityManager s = System.getSecurityManager();
			this.group = (s != null) ? s.getThreadGroup() : group;
			namePrefix = poolName + " - ";
		}
		
		
		public Thread newThread(Runnable r) {
			logger.debug("creating new thread" );
			
//			Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());
			CreationAwareThread t = new CreationAwareThread(group, r, namePrefix + threadNumber.getAndIncrement());
			t.setDaemon(false);
			if (t.getPriority() != Thread.NORM_PRIORITY)
				t.setPriority(Thread.NORM_PRIORITY);
			
			return t;
		}
		
		
		
		static class CreationAwareThread extends Thread {
			WeakReference<Thread> creatorThread;
			String creatorThreadName;
			StackTraceElement[] startTimeStackTraceOfCreatorThread;
			
			public CreationAwareThread( ThreadGroup group, Runnable r, String name ) {
				super(group, r, name);
			}
			
			@Override
			public synchronized void start() {
				this.creatorThread = new WeakReference<Thread>(Thread.currentThread());
				this.creatorThreadName = Thread.currentThread().getName();
				this.startTimeStackTraceOfCreatorThread = Thread.currentThread().getStackTrace();
				super.start();
			}
			
			/**
			 * @return the creatorThread
			 */
			public WeakReference<Thread> getCreatorThread() {
				return creatorThread;
			}
			
			/**
			 * @param creatorThread
			 * the creatorThread to set
			 */
			public void setCreatorThread(WeakReference<Thread> creatorThread) {
				this.creatorThread = creatorThread;
			}
			
			/**
			 * @return the creatorThreadName
			 */
			public String getCreatorThreadName() {
				return creatorThreadName;
			}
			
			/**
			 * @param creatorThreadName
			 * the creatorThreadName to set
			 */
			public void setCreatorThreadName(String creatorThreadName) {
				this.creatorThreadName = creatorThreadName;
			}
			
			/**
			 * @return the startTimeStackTraceOfCreatorThread
			 */
			public StackTraceElement[] getStartTimeStackTraceOfCreatorThread() {
				return startTimeStackTraceOfCreatorThread;
			}
			
			/**
			 * @param startTimeStackTraceOfCreatorThread
			 * the startTimeStackTraceOfCreatorThread to set
			 */
			public void setStartTimeStackTraceOfCreatorThread(
					StackTraceElement[] startTimeStackTraceOfCreatorThread) {
				this.startTimeStackTraceOfCreatorThread = startTimeStackTraceOfCreatorThread;
			}
		}
}
```


Ich arbeite leider nicht wie Thomas in seinem Beispiel mit inneren Klassen. Sondern habe jeden Thread in einer eigenen Klasse welche das Interface Callable implementiert um mittels des Future Objects ein Ergebnis in den Starter Thread zurück zu übergeben.

Ich habe nun folgende Strucktur:
- main: startet mehrere Threads in einer Threadgroup 'Job Threads'
- Thread in 'Job Threads' : macht nun unter anderem folgendes:
erzeugt eine ThreadFactory Instanz
erzeugt ein ExecuterService (newCachedThreadPool) mit der ThreadFactory
benutzt die submit Methode des ExecutorService. [ submit( new ThreadedClass( ... Konstruktorparameter ...)) ] um mehrere SubThread zu starten.
Wartet mittels der get Methode auf den Rückgabewert aller SubThreads.


----------



## Thomas Darimont (9. August 2007)

Hallo,

die statischen inneren Klassen bzw. die anonymen inneren Klassen benutze ich nur, damit ich das ganze schneller abtippen kann. Die kann man ja ganz leicht per Refactoring zur einer richtigen top-level Klasse machen.

Ich würde hier einfach immer den selben ExecutorService verwenden und nicht immer einen neuen bauen...

schau mal hier:

```
/**
 * 
 */
package de.tutorials;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author Thomas.Darimont
 * 
 */
public class CreationInfoAwareThreadingExample {

    /**
     * @param args
     */
    public static void main(String[] args) {
        final ExecutorService executorService = Executors
                .newCachedThreadPool(createCreationAwareThreadFactory());

        Runnable job = createJob(executorService);

        executorService.execute(job);
        executorService.execute(job);
        executorService.execute(job);

    }

    /**
     * @param executorService
     * @return
     */
    private static Runnable createJob(final ExecutorService executorService) {
        Runnable job = new Runnable() {
            public void run() {
                final String jobId = String.valueOf(System.nanoTime());
                System.out.println("Executing job: " + jobId);

                Callable<String> task = createTask(jobId);

                final List<Future<String>> futureTaskResults = new CopyOnWriteArrayList<Future<String>>();
                for (int i = 0; i < 3; i++) {
                    futureTaskResults.add(executorService.submit(task));
                }

                Callable<List<String>> resultRetriever = createResultRetriever(
                        jobId, futureTaskResults);

                Future<List<String>> futureResults = executorService
                        .submit(resultRetriever);

                try {
                    System.out.printf("finished job: %s with results: %s\n",
                            jobId, futureResults.get());
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        };
        return job;
    }

    /**
     * 
     * @param jobId
     * @param futureTaskResults
     * @return
     */
    private static Callable<List<String>> createResultRetriever(
            final String jobId, final List<Future<String>> futureTaskResults) {
        Callable<List<String>> resultRetriever = new Callable<List<String>>() {
            public List<String> call() throws Exception {
                List<String> results = new ArrayList<String>();
                while (!futureTaskResults.isEmpty()) {
                    for (Future<String> futureTaskResult : futureTaskResults) {
                        System.out
                                .println("Checking for completion of tasks in job: "
                                        + jobId);
                        try {
                            results.add(futureTaskResult.get(3,
                                    TimeUnit.SECONDS));
                            futureTaskResults.remove(futureTaskResult);
                        } catch (TimeoutException e) {
                            System.out
                                    .printf(
                                            "Got time out while checking for completion of tasks in job: %s trying again...\n",
                                            jobId);
                            continue;
                            // e.printStackTrace();
                        }
                    }
                }
                return results;
            }
        };
        return resultRetriever;
    }

    /**
     * 
     * @param jobId
     * @return
     */
    private static Callable<String> createTask(final String jobId) {
        Callable<String> task = new Callable<String>() {
            public String call() throws Exception {

                if (Thread.currentThread() instanceof CreationInfoAwareThread) {
                    CreationInfoAwareThread creationInfoAwareThread = (CreationInfoAwareThread) Thread
                            .currentThread();
                    String creatorThreadName = creationInfoAwareThread
                            .getCreatorThreadName();
                    // ...
                }

                String taskId = String.valueOf(System.nanoTime());
                System.out.printf("Executing task %s within: %s\n", taskId,
                        jobId);
                TimeUnit.SECONDS.sleep((long) (Math.random() * 10 + 3));
                System.out.printf("Completed task: %s within: %s\n", taskId,
                        jobId);
                return taskId;
            }
        };
        return task;
    }

    /**
     * 
     * @return
     */
    private static ThreadFactory createCreationAwareThreadFactory() {
        return new ThreadFactory() {
            public Thread newThread(Runnable r) {
                return new CreationInfoAwareThread(r);
            }
        };
    }

    /**
     * 
     * @author Thomas.Darimont
     *
     */
    static class CreationInfoAwareThread extends Thread {
        WeakReference<Thread> creatorThread;
        String creatorThreadName;
        StackTraceElement[] startTimeStackTraceOfCreatorThread;

        /**
         * 
         * @param r
         */
        public CreationInfoAwareThread(Runnable r) {
            super(r, "CreationInfoAwareThread " + System.currentTimeMillis());
        }

        /**
         * 
         */
        @Override
        public synchronized void start() {
            this.creatorThread = new WeakReference<Thread>(Thread
                    .currentThread());
            this.creatorThreadName = Thread.currentThread().getName();
            this.startTimeStackTraceOfCreatorThread = Thread.currentThread()
                    .getStackTrace();
            super.start();
        }

        /**
         * @return the creatorThread
         */
        public WeakReference<Thread> getCreatorThread() {
            return creatorThread;
        }

        /**
         * @param creatorThread
         *            the creatorThread to set
         */
        public void setCreatorThread(WeakReference<Thread> creatorThread) {
            this.creatorThread = creatorThread;
        }

        /**
         * @return the creatorThreadName
         */
        public String getCreatorThreadName() {
            return creatorThreadName;
        }

        /**
         * @param creatorThreadName
         *            the creatorThreadName to set
         */
        public void setCreatorThreadName(String creatorThreadName) {
            this.creatorThreadName = creatorThreadName;
        }

        /**
         * @return the startTimeStackTraceOfCreatorThread
         */
        public StackTraceElement[] getStartTimeStackTraceOfCreatorThread() {
            return startTimeStackTraceOfCreatorThread;
        }

        /**
         * @param startTimeStackTraceOfCreatorThread
         *            the startTimeStackTraceOfCreatorThread to set
         */
        public void setStartTimeStackTraceOfCreatorThread(
                StackTraceElement[] startTimeStackTraceOfCreatorThread) {
            this.startTimeStackTraceOfCreatorThread = startTimeStackTraceOfCreatorThread;
        }
    }
}
```


Ausgabe:

```
Executing job: 47013040352894
Executing job: 47013045433427
Executing task 47013048172602 within: 47013045433427
Executing task 47013075729177 within: 47013040352894
Executing task 47013076356073 within: 47013045433427
Executing job: 47013077198638
Executing task 47013077710714 within: 47013040352894
Checking for completion of tasks in job: 47013045433427
Executing task 47013081683286 within: 47013077198638
Checking for completion of tasks in job: 47013077198638
Executing task 47013082836226 within: 47013045433427
Executing task 47013083683820 within: 47013040352894
Checking for completion of tasks in job: 47013040352894
Executing task 47013084467998 within: 47013077198638
Executing task 47013084931744 within: 47013077198638
Completed task: 47013081683286 within: 47013077198638
Got time out while checking for completion of tasks in job: 47013045433427 trying again...
Checking for completion of tasks in job: 47013045433427
Got time out while checking for completion of tasks in job: 47013077198638 trying again...
Checking for completion of tasks in job: 47013077198638
Checking for completion of tasks in job: 47013077198638
Got time out while checking for completion of tasks in job: 47013040352894 trying again...
Checking for completion of tasks in job: 47013040352894
Completed task: 47013075729177 within: 47013040352894
Completed task: 47013076356073 within: 47013045433427
Completed task: 47013082836226 within: 47013045433427
Checking for completion of tasks in job: 47013045433427
Checking for completion of tasks in job: 47013045433427
Completed task: 47013048172602 within: 47013045433427
finished job: 47013045433427 with results: [47013082836226, 47013076356073, 47013048172602]
Completed task: 47013077710714 within: 47013040352894
Got time out while checking for completion of tasks in job: 47013077198638 trying again...
Checking for completion of tasks in job: 47013077198638
Got time out while checking for completion of tasks in job: 47013040352894 trying again...
Checking for completion of tasks in job: 47013040352894
Checking for completion of tasks in job: 47013040352894
Checking for completion of tasks in job: 47013040352894
Completed task: 47013083683820 within: 47013040352894
finished job: 47013040352894 with results: [47013075729177, 47013077710714, 47013083683820]
Got time out while checking for completion of tasks in job: 47013077198638 trying again...
Checking for completion of tasks in job: 47013077198638
Completed task: 47013084467998 within: 47013077198638
Completed task: 47013084931744 within: 47013077198638
Checking for completion of tasks in job: 47013077198638
finished job: 47013077198638 with results: [47013081683286, 47013084467998, 47013084931744]
```

Weitere Beispiele zum ExecutorService gibts hier:
http://www.tutorials.de/forum/java/274056-fragen-threads-und-executorservice.html
http://www.tutorials.de/forum/java/276266-komplizierter-java-queue-mechanismus.html
http://www.tutorials.de/forum/java/271591-jface-tree-knoten-verzoegert-nachladen.html
http://www.tutorials.de/forum/java/236989-thread-pool-pattern.html

Gruß Tom


----------



## DerMartin007 (10. August 2007)

Danke Thomas für die super Hilfe und den ganzen Beispiel Code.

Einiges über den ExecutorService hatte ich mir schon anhand deiner Beitrage hier angeschaut.
Ich werde mir dein Beispiel mal in Ruhe anschauen. Genau soetwas brauche ich nämlich auch an einer anderen Stelle noch. 

Nochmals viele Dank für deine super Hilfe und das auch noch so spät am Abend.


----------



## DerMartin007 (20. August 2007)

Hallo alle zusammen. Jetzt hatte ich gedacht das ich mein Problem dank der tollen Hilfe von Thomas gelöst habe. Da stolper ich über Probleme mit dem ExecutorService 

Da ich meine Job Threads leider auf eine bestimmte Anzahl begrenzen muß dachte ich mir ich benutze 2 Executoer Services. Einen mit einem fixedThreadPool und einen mit einem cachedThreadPool. Dies nur als Anmerkung für meine Codeänderungen.

Ich denke das mein Problem die Wiederverwertung von Threads des ExecutorServices ist. Denn mir ist folgendes aufgefallen:
-  das zum einen die start() methode wohl, nachdem ein freier Thread existiert, nicht mehr durchlaufen wird. Zu sehen das nach 4 'Task' Threads die Ausgabe 'start Methode' nicht ausgegeben wird. Hierdurch denke ich das auch die Membervariable 'startTimeStackTraceOfCreatorThread' nicht richtig gefüllt ist. Ich glaube sie beinhaltet noch die Werte vom ersten Thread.
- zum 2 benutze ich log4j als logger. Dieser loggt nun sinnvollerweise für mich den Thread Namen immer mit aus. Dieses wollte ich nun auch nutzen um die Logausgaben der verschiedenen Threads zu unterscheiden. Leider ist auch dieser immer gleich dem vom ersten Thread.

Hier mein abgeänderter Beispielcode:

```
/**
 *
 */
package de.tutorials;

import java.lang.ref.WeakReference;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;

import de.tutorials.CreationInfoAwareThreadingExample.CreationAwareThreadFactory.CreationInfoAwareThread;
import de.tutorials.CreationInfoAwareThreadingExample.ExecutorServiceHelper.Exec;





/**
 * @author Thomas.Darimont
 *
 */
public class CreationInfoAwareThreadingExample {

	private static Logger logger = Logger.getRootLogger();

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		ExecutorService executor = ExecutorServiceHelper.getInstance( Exec.JOB );

		logger.info( "Start main ...");

		try {
			for ( int i = 0; i<3; i++) {

				Runnable job = createJob( "Job Thread " + i + " ");
				executor.execute(job);
			}


			executor.shutdown();
			executor.awaitTermination(30, TimeUnit.SECONDS);
		} catch (Exception e) {
			logger.error( "EXCEPTION");
		}
		logger.info( "End main.");
	}



	/**
	 * @param executorService
	 * @return
	 */
	private static Runnable createJob( final String name) {
		logger.info( "create " + name);
		
		Runnable job = new Runnable() {

			public void run() {
				final String jobId = name;
				Thread.currentThread().setName(jobId);

				logger.info("Executing job: " + jobId);
				
				ExecutorService executorService = ExecutorServiceHelper.getInstance( Exec.TASK );
				
				Callable<Object> task = createTask(jobId);

				final List<Future<Object>> futureTaskResults = new CopyOnWriteArrayList<Future<Object>>();

				for (int i = 0; i < 3; i++) {
					futureTaskResults.add(executorService.submit( task));
				}

				Callable<List<Object>> resultRetriever = ExecutorServiceHelper.createResultRetriever(jobId, futureTaskResults);

				Future<List<Object>> futureResults = executorService.submit(resultRetriever);

				try {
					logger.info("finished job: " + jobId + "  with results: " + futureResults.get() );
				} catch (InterruptedException e) {
					e.printStackTrace();

				} catch (ExecutionException e) {
					e.printStackTrace();

				}

			}

		};

		return job;
	}



	/**
	 *
	 * @param jobId
	 * @return
	 */
	private static Callable<Object> createTask(final String jobId) {

		Callable<Object> task = new Callable<Object>() {

			public String call() throws Exception {

				if (Thread.currentThread() instanceof CreationInfoAwareThread) {
					CreationInfoAwareThread creationInfoAwareThread = (CreationInfoAwareThread) Thread.currentThread();
					String creatorThreadName = creationInfoAwareThread.getCreatorThreadName();

					// ...

				}

				String taskId = String.valueOf(System.nanoTime());
				logger.info( "Executing task " + taskId + " within: " + jobId );

				TimeUnit.SECONDS.sleep((long) (Math.random() * 10 + 3));

				logger.info("Completed task: " + taskId + " within: " + jobId);

				return taskId;
			}
		};
		return task;
	}



	
	public static class CreationAwareThreadFactory implements ThreadFactory {
		
		ThreadGroup group;
		AtomicInteger threadUniqueID = new AtomicInteger(1);
		String nameSuffix;
		
		private Logger logger = Logger.getRootLogger();
		
		
		public CreationAwareThreadFactory() {
			this( Thread.currentThread().getThreadGroup().getName(), Thread.currentThread().getThreadGroup() );
		}
		
		public CreationAwareThreadFactory( String poolName ) {
			this( poolName, Thread.currentThread().getThreadGroup() );
		}
		
		public CreationAwareThreadFactory( String poolName, String threadGroupName ) {
			this( poolName, new ThreadGroup( threadGroupName ) );
		}
		
		public CreationAwareThreadFactory( String poolName, ThreadGroup group ) {
			logger.debug("ThreadFactory (" + poolName + ")");
			this.nameSuffix = poolName;
			
			SecurityManager s = System.getSecurityManager();
			this.group = (s != null) ? s.getThreadGroup() : group;
		}
		
		public synchronized Thread newThread(Runnable r) {
			String threadName = Thread.currentThread().getName() + "-" + nameSuffix + "-" + threadUniqueID.getAndIncrement();
			logger.debug( "creating new thread (Thread Group: " + group.getName() + ", Thread Name: " + threadName + ")" );
			Thread t = new CreationInfoAwareThread(group, r, threadName );
			return t;
		}
		
		
		
		/**
		 *
		 */
		public static class CreationInfoAwareThread extends Thread {
			WeakReference<Thread> creatorThread;
			String creatorThreadName;
			StackTraceElement[] startTimeStackTraceOfCreatorThread;
			
			private Logger logger = Logger.getRootLogger();
			
			
			/**
			 *
			 * @param r
			 */
			public CreationInfoAwareThread(ThreadGroup group, Runnable r, String threadName) {
				super(group, r, threadName);
			}

			/**
			 *
			 */
			@Override
			public synchronized void start() {
				this.creatorThread = new WeakReference<Thread>(Thread.currentThread());
				this.creatorThreadName = Thread.currentThread().getName();
				this.startTimeStackTraceOfCreatorThread = Thread.currentThread().getStackTrace();
				logger.debug( "start Methode" );
				super.start();
			}


			/**
			 * @return the creatorThread
			 */
			public WeakReference<Thread> getCreatorThread() {
				return creatorThread;
			}

			/**
			 * @param creatorThread
			 *            the creatorThread to set
			 */
			public void setCreatorThread(WeakReference<Thread> creatorThread) {
				this.creatorThread = creatorThread;
			}

			/**
			 * @return the creatorThreadName
			 */
			public String getCreatorThreadName() {
				return creatorThreadName;
			}

			/**
			 * @param creatorThreadName
			 *            the creatorThreadName to set
			 */
			public void setCreatorThreadName(String creatorThreadName) {
				this.creatorThreadName = creatorThreadName;
			}

			/**
			 * @return the startTimeStackTraceOfCreatorThread
			 */
			public StackTraceElement[] getStartTimeStackTraceOfCreatorThread() {
				return startTimeStackTraceOfCreatorThread;
			}

			/**
			 * @param startTimeStackTraceOfCreatorThread
			 *            the startTimeStackTraceOfCreatorThread to set
			 */
			public void setStartTimeStackTraceOfCreatorThread(StackTraceElement[] startTimeStackTraceOfCreatorThread) {
				this.startTimeStackTraceOfCreatorThread = startTimeStackTraceOfCreatorThread;
			}
			
			/**
			 * Logs the Stack Trace of the creator thread
			 */
			public void logStartTimeStackTraceOfCreatorThread() {
				Throwable throwable = new Throwable();
				throwable.setStackTrace( getStartTimeStackTraceOfCreatorThread() );
				logger.info( "Stack Trace of creator Thread:", throwable );
			}
		}
	}




	public static class ExecutorServiceHelper {

		public enum Exec { DEFAULT, JOB, TASK, RESULT_RETRIEVER }


		public static int maxParallelJobs = 1;

		private static ExecutorService defaultInstance = null;
		private static ExecutorService jobExecutorInstance = null;
		private static ExecutorService taskExecutorInstance = null;
		private static ExecutorService resultRetrieverExecutorInstance = null;

		private static Logger logger = Logger.getRootLogger();


		/**
		 * Get the default ExecutorService Instance
		 * 
		 * @return ExecutorService Instance
		 */
		public static synchronized ExecutorService getInstance() {
			return getInstance( Exec.DEFAULT );
		}

		/**
		 * Get a given ExecutorService Instance
		 * 
		 * @param executor
		 * @return ExecutorService Instance
		 */
		public static synchronized ExecutorService getInstance( Exec executor ) {
			ExecutorService instance = null;

			switch ( executor ) {
			case JOB:
				if (jobExecutorInstance == null)
					jobExecutorInstance = Executors.newFixedThreadPool( maxParallelJobs, new CreationAwareThreadFactory( "Job", "JobThreads" ));
				instance = jobExecutorInstance;
				break;
			case TASK:
				if (taskExecutorInstance == null)
					taskExecutorInstance = Executors.newCachedThreadPool( new CreationAwareThreadFactory( "Task", "TaskThreads" ));
				instance = taskExecutorInstance;
				break;
			case RESULT_RETRIEVER:
				if (resultRetrieverExecutorInstance == null)
					resultRetrieverExecutorInstance = Executors.newCachedThreadPool( new CreationAwareThreadFactory( "ResultRetriever", "ResultRetrieverThreads" ));
				instance = resultRetrieverExecutorInstance;
				break;
			default:
				if (defaultInstance == null)
					defaultInstance = Executors.newCachedThreadPool();
			instance = defaultInstance;
			}

			return instance;
		}

		/**
		 * Creates a Result Retriever task
		 *
		 * @param jobId
		 * @param futureTaskResults
		 * @return Callable List of Objects
		 */
		public static Callable<List<Object>> createResultRetriever(final String jobId, final List<Future<Object>> futureTaskResults) {

			Callable<List<Object>> resultRetriever = new Callable<List<Object>>() {
				public List<Object> call() throws Exception {
					logger.debug( "Checking for completion of tasks in job: '"+ jobId + "'" );

					List<Object> results = new ArrayList<Object>();
					while (!futureTaskResults.isEmpty()) {
						for (Future<Object> futureTaskResult : futureTaskResults) {
							try {
								results.add( futureTaskResult.get( 3,TimeUnit.SECONDS ) );
								futureTaskResults.remove( futureTaskResult );
							} catch (TimeoutException e) {
								logger.debug( "Got time out while checking for completion of tasks in job: '" + jobId + "' trying again..." );
								continue;
							}
						}
					}
					logger.debug( "All tasks in job '" + jobId + "' completed." );
					return results;
				}
			};
			return resultRetriever;
		}
	} 
}
```

Dieser liefert folgende Ausgabe:

```
2007-08-20 00:56:05,533 DEBUG [main]: ThreadFactory (Job)
2007-08-20 00:56:05,773 INFO  [main]: Start main ...
2007-08-20 00:56:05,773 INFO  [main]: create Job Thread 0 
2007-08-20 00:56:05,783 DEBUG [main]: creating new thread (Thread Group: JobThreads, Thread Name: main-Job-1)
2007-08-20 00:56:05,783 DEBUG [main]: start Methode
2007-08-20 00:56:05,783 INFO  [main]: create Job Thread 1 
2007-08-20 00:56:05,783 INFO  [main]: create Job Thread 2 
2007-08-20 00:56:05,783 INFO  [Job Thread 0 ]: Executing job: Job Thread 0 
2007-08-20 00:56:05,783 DEBUG [Job Thread 0 ]: ThreadFactory (Task)
2007-08-20 00:56:05,873 DEBUG [Job Thread 0 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 0 -Task-1)
2007-08-20 00:56:05,873 DEBUG [Job Thread 0 ]: start Methode
2007-08-20 00:56:05,883 DEBUG [Job Thread 0 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 0 -Task-2)
2007-08-20 00:56:05,883 DEBUG [Job Thread 0 ]: start Methode
2007-08-20 00:56:05,883 DEBUG [Job Thread 0 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 0 -Task-3)
2007-08-20 00:56:05,883 INFO  [Job Thread 0 -Task-2]: Executing task 12660818149513 within: Job Thread 0 
2007-08-20 00:56:05,883 INFO  [Job Thread 0 -Task-1]: Executing task 12660817629614 within: Job Thread 0 
2007-08-20 00:56:06,044 DEBUG [Job Thread 0 ]: start Methode
2007-08-20 00:56:06,044 INFO  [Job Thread 0 -Task-3]: Executing task 12660977205203 within: Job Thread 0 
2007-08-20 00:56:06,434 DEBUG [Job Thread 0 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 0 -Task-4)
2007-08-20 00:56:06,434 DEBUG [Job Thread 0 ]: start Methode
2007-08-20 00:56:06,434 DEBUG [Job Thread 0 -Task-4]: Checking for completion of tasks in job: 'Job Thread 0 '
2007-08-20 00:56:09,448 DEBUG [Job Thread 0 -Task-4]: Got time out while checking for completion of tasks in job: 'Job Thread 0 ' trying again...
2007-08-20 00:56:12,513 DEBUG [Job Thread 0 -Task-4]: Got time out while checking for completion of tasks in job: 'Job Thread 0 ' trying again...
2007-08-20 00:56:13,044 INFO  [Job Thread 0 -Task-2]: Completed task: 12660818149513 within: Job Thread 0 
2007-08-20 00:56:15,047 INFO  [Job Thread 0 -Task-1]: Completed task: 12660817629614 within: Job Thread 0 
2007-08-20 00:56:15,607 DEBUG [Job Thread 0 -Task-4]: Got time out while checking for completion of tasks in job: 'Job Thread 0 ' trying again...
2007-08-20 00:56:17,049 INFO  [Job Thread 0 -Task-3]: Completed task: 12660977205203 within: Job Thread 0 
2007-08-20 00:56:17,059 DEBUG [Job Thread 0 -Task-4]: All tasks in job 'Job Thread 0 ' completed.
2007-08-20 00:56:17,059 INFO  [Job Thread 0 ]: finished job: Job Thread 0   with results: [12660817629614, 12660818149513, 12660977205203]
2007-08-20 00:56:17,059 INFO  [Job Thread 1 ]: Executing job: Job Thread 1 
2007-08-20 00:56:17,059 DEBUG [Job Thread 1 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 1 -Task-5)
2007-08-20 00:56:17,059 DEBUG [Job Thread 1 ]: start Methode
2007-08-20 00:56:17,059 INFO  [Job Thread 0 -Task-1]: Executing task 12671878183400 within: Job Thread 1 
2007-08-20 00:56:17,059 DEBUG [Job Thread 1 -Task-5]: Checking for completion of tasks in job: 'Job Thread 1 '
2007-08-20 00:56:17,059 INFO  [Job Thread 0 -Task-4]: Executing task 12671878602727 within: Job Thread 1 
2007-08-20 00:56:17,059 INFO  [Job Thread 0 -Task-2]: Executing task 12671878425051 within: Job Thread 1 
2007-08-20 00:56:20,164 DEBUG [Job Thread 1 -Task-5]: Got time out while checking for completion of tasks in job: 'Job Thread 1 ' trying again...
2007-08-20 00:56:23,078 INFO  [Job Thread 0 -Task-4]: Completed task: 12671878602727 within: Job Thread 1 
2007-08-20 00:56:23,298 DEBUG [Job Thread 1 -Task-5]: Got time out while checking for completion of tasks in job: 'Job Thread 1 ' trying again...
2007-08-20 00:56:26,373 DEBUG [Job Thread 1 -Task-5]: Got time out while checking for completion of tasks in job: 'Job Thread 1 ' trying again...
2007-08-20 00:56:28,075 INFO  [Job Thread 0 -Task-1]: Completed task: 12671878183400 within: Job Thread 1 
2007-08-20 00:56:29,087 INFO  [Job Thread 0 -Task-2]: Completed task: 12671878425051 within: Job Thread 1 
2007-08-20 00:56:29,087 DEBUG [Job Thread 1 -Task-5]: All tasks in job 'Job Thread 1 ' completed.
2007-08-20 00:56:29,087 INFO  [Job Thread 1 ]: finished job: Job Thread 1   with results: [12671878602727, 12671878183400, 12671878425051]
2007-08-20 00:56:29,087 INFO  [Job Thread 2 ]: Executing job: Job Thread 2 
2007-08-20 00:56:29,107 INFO  [Job Thread 0 -Task-2]: Executing task 12683641632665 within: Job Thread 2 
2007-08-20 00:56:29,107 INFO  [Job Thread 0 -Task-4]: Executing task 12683642031878 within: Job Thread 2 
2007-08-20 00:56:29,107 DEBUG [Job Thread 0 -Task-3]: Checking for completion of tasks in job: 'Job Thread 2 '
2007-08-20 00:56:29,107 INFO  [Job Thread 0 -Task-1]: Executing task 12683643348805 within: Job Thread 2 
2007-08-20 00:56:32,181 DEBUG [Job Thread 0 -Task-3]: Got time out while checking for completion of tasks in job: 'Job Thread 2 ' trying again...
2007-08-20 00:56:35,115 INFO  [Job Thread 0 -Task-2]: Completed task: 12683641632665 within: Job Thread 2 
2007-08-20 00:56:35,276 DEBUG [Job Thread 0 -Task-3]: Got time out while checking for completion of tasks in job: 'Job Thread 2 ' trying again...
2007-08-20 00:56:36,347 INFO  [main]: End main.
2007-08-20 00:56:38,390 DEBUG [Job Thread 0 -Task-3]: Got time out while checking for completion of tasks in job: 'Job Thread 2 ' trying again...
2007-08-20 00:56:39,101 INFO  [Job Thread 0 -Task-1]: Completed task: 12683643348805 within: Job Thread 2 
2007-08-20 00:56:41,104 INFO  [Job Thread 0 -Task-4]: Completed task: 12683642031878 within: Job Thread 2 
2007-08-20 00:56:41,104 DEBUG [Job Thread 0 -Task-3]: All tasks in job 'Job Thread 2 ' completed.
2007-08-20 00:56:41,104 INFO  [Job Thread 2 ]: finished job: Job Thread 2   with results: [12683641632665, 12683643348805, 12683642031878]
```

Ich möchte aber diese Ausgabe haben (mir geht es um den Threadnamen zwischen [ ]):

```
2007-08-20 00:56:05,533 DEBUG [main]: ThreadFactory (Job)
2007-08-20 00:56:05,773 INFO  [main]: Start main ...
2007-08-20 00:56:05,773 INFO  [main]: create Job Thread 0 
2007-08-20 00:56:05,783 DEBUG [main]: creating new thread (Thread Group: JobThreads, Thread Name: main-Job-1)
2007-08-20 00:56:05,783 DEBUG [main]: start Methode
2007-08-20 00:56:05,783 INFO  [main]: create Job Thread 1 
2007-08-20 00:56:05,783 INFO  [main]: create Job Thread 2 
2007-08-20 00:56:05,783 INFO  [Job Thread 0 ]: Executing job: Job Thread 0 
2007-08-20 00:56:05,783 DEBUG [Job Thread 0 ]: ThreadFactory (Task)
2007-08-20 00:56:05,873 DEBUG [Job Thread 0 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 0 -Task-1)
2007-08-20 00:56:05,873 DEBUG [Job Thread 0 ]: start Methode
2007-08-20 00:56:05,883 DEBUG [Job Thread 0 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 0 -Task-2)
2007-08-20 00:56:05,883 DEBUG [Job Thread 0 ]: start Methode
2007-08-20 00:56:05,883 DEBUG [Job Thread 0 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 0 -Task-3)
2007-08-20 00:56:05,883 INFO  [Job Thread 0 -Task-2]: Executing task 12660818149513 within: Job Thread 0 
2007-08-20 00:56:05,883 INFO  [Job Thread 0 -Task-1]: Executing task 12660817629614 within: Job Thread 0 
2007-08-20 00:56:06,044 DEBUG [Job Thread 0 ]: start Methode
2007-08-20 00:56:06,044 INFO  [Job Thread 0 -Task-3]: Executing task 12660977205203 within: Job Thread 0 
2007-08-20 00:56:06,434 DEBUG [Job Thread 0 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 0 -Task-4)
2007-08-20 00:56:06,434 DEBUG [Job Thread 0 ]: start Methode
2007-08-20 00:56:06,434 DEBUG [Job Thread 0 -Task-4]: Checking for completion of tasks in job: 'Job Thread 0 '
2007-08-20 00:56:09,448 DEBUG [Job Thread 0 -Task-4]: Got time out while checking for completion of tasks in job: 'Job Thread 0 ' trying again...
2007-08-20 00:56:12,513 DEBUG [Job Thread 0 -Task-4]: Got time out while checking for completion of tasks in job: 'Job Thread 0 ' trying again...
2007-08-20 00:56:13,044 INFO  [Job Thread 0 -Task-2]: Completed task: 12660818149513 within: Job Thread 0 
2007-08-20 00:56:15,047 INFO  [Job Thread 0 -Task-1]: Completed task: 12660817629614 within: Job Thread 0 
2007-08-20 00:56:15,607 DEBUG [Job Thread 0 -Task-4]: Got time out while checking for completion of tasks in job: 'Job Thread 0 ' trying again...
2007-08-20 00:56:17,049 INFO  [Job Thread 0 -Task-3]: Completed task: 12660977205203 within: Job Thread 0 
2007-08-20 00:56:17,059 DEBUG [Job Thread 0 -Task-4]: All tasks in job 'Job Thread 0 ' completed.
2007-08-20 00:56:17,059 INFO  [Job Thread 0 ]: finished job: Job Thread 0   with results: [12660817629614, 12660818149513, 12660977205203]
2007-08-20 00:56:17,059 INFO  [Job Thread 1 ]: Executing job: Job Thread 1 
2007-08-20 00:56:17,059 DEBUG [Job Thread 1 ]: creating new thread (Thread Group: TaskThreads, Thread Name: Job Thread 1 -Task-5)
2007-08-20 00:56:17,059 DEBUG [Job Thread 1 ]: start Methode
2007-08-20 00:56:17,059 INFO  [Job Thread 1 -Task-1]: Executing task 12671878183400 within: Job Thread 1 
2007-08-20 00:56:17,059 DEBUG [Job Thread 1 -Task-5]: Checking for completion of tasks in job: 'Job Thread 1 '
2007-08-20 00:56:17,059 INFO  [Job Thread 1 -Task-4]: Executing task 12671878602727 within: Job Thread 1 
2007-08-20 00:56:17,059 INFO  [Job Thread 1 -Task-2]: Executing task 12671878425051 within: Job Thread 1 
2007-08-20 00:56:20,164 DEBUG [Job Thread 1 -Task-5]: Got time out while checking for completion of tasks in job: 'Job Thread 1 ' trying again...
2007-08-20 00:56:23,078 INFO  [Job Thread 1 -Task-4]: Completed task: 12671878602727 within: Job Thread 1 
2007-08-20 00:56:23,298 DEBUG [Job Thread 1 -Task-5]: Got time out while checking for completion of tasks in job: 'Job Thread 1 ' trying again...
2007-08-20 00:56:26,373 DEBUG [Job Thread 1 -Task-5]: Got time out while checking for completion of tasks in job: 'Job Thread 1 ' trying again...
2007-08-20 00:56:28,075 INFO  [Job Thread 1 -Task-1]: Completed task: 12671878183400 within: Job Thread 1 
2007-08-20 00:56:29,087 INFO  [Job Thread 1 -Task-2]: Completed task: 12671878425051 within: Job Thread 1 
2007-08-20 00:56:29,087 DEBUG [Job Thread 1 -Task-5]: All tasks in job 'Job Thread 1 ' completed.
2007-08-20 00:56:29,087 INFO  [Job Thread 1 ]: finished job: Job Thread 1   with results: [12671878602727, 12671878183400, 12671878425051]
2007-08-20 00:56:29,087 INFO  [Job Thread 2 ]: Executing job: Job Thread 2 
2007-08-20 00:56:29,107 INFO  [Job Thread 2 -Task-2]: Executing task 12683641632665 within: Job Thread 2 
2007-08-20 00:56:29,107 INFO  [Job Thread 2 -Task-4]: Executing task 12683642031878 within: Job Thread 2 
2007-08-20 00:56:29,107 DEBUG [Job Thread 2 -Task-3]: Checking for completion of tasks in job: 'Job Thread 2 '
2007-08-20 00:56:29,107 INFO  [Job Thread 2 -Task-1]: Executing task 12683643348805 within: Job Thread 2 
2007-08-20 00:56:32,181 DEBUG [Job Thread 2 -Task-3]: Got time out while checking for completion of tasks in job: 'Job Thread 2 ' trying again...
2007-08-20 00:56:35,115 INFO  [Job Thread 2 -Task-2]: Completed task: 12683641632665 within: Job Thread 2 
2007-08-20 00:56:35,276 DEBUG [Job Thread 2 -Task-3]: Got time out while checking for completion of tasks in job: 'Job Thread 2 ' trying again...
2007-08-20 00:56:36,347 INFO  [main]: End main.
2007-08-20 00:56:38,390 DEBUG [Job Thread 2 -Task-3]: Got time out while checking for completion of tasks in job: 'Job Thread 2 ' trying again...
2007-08-20 00:56:39,101 INFO  [Job Thread 2 -Task-1]: Completed task: 12683643348805 within: Job Thread 2 
2007-08-20 00:56:41,104 INFO  [Job Thread 2 -Task-4]: Completed task: 12683642031878 within: Job Thread 2 
2007-08-20 00:56:41,104 DEBUG [Job Thread 2 -Task-3]: All tasks in job 'Job Thread 2 ' completed.
2007-08-20 00:56:41,104 INFO  [Job Thread 2 ]: finished job: Job Thread 2   with results: [12683641632665, 12683643348805, 12683642031878]
```

Ich hoffe das mir jemand helfen kann.

Gruß
Martin


----------



## Thomas Darimont (20. August 2007)

Hallo,

okay, das die Threads da wiederverwendet werden hab ich doch glatt unter den Tisch fallen lassen ;-)

Die start() Methode von Thread wird im Lebenszyklus eines Threads natürlich nur einmal aufgerufen. Die start() Methode ist dort aber die letzte (?) Stelle vor dem eigentlichen Thread Start wo du auf den CallerStackTrace des aufrufenden Threads zugreiffen kannst. Entweder verhinderst du das deine Threads wiederverwendet werden (dann solltest du hier aber keinen ThreadPool verwenden) oder du merkst dir die StackTrace Informationen des Aufrufers entsprechend früher (und nicht bei Thread.start())

Gruß Tom


----------



## Thomas Darimont (21. August 2007)

Hallo,

so sollte es jetzt funktionieren. Die Threadinformation hängt nun nicht mehr am Thread sondern am Runnable.


```
/**
 * 
 */
package de.tutorials;

import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author Thomas.Darimont
 * 
 */
public class CreationInfoAwareThreadingExample {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final ExecutorService executorService = (ExecutorService) Proxy
				.newProxyInstance(Object.class.getClassLoader(),
						new Class[] { ExecutorService.class },
						new ThreadCreationInfoAwareExecutorInterceptor(Executors
								.newCachedThreadPool()));

		executorService.execute(createJob(executorService)); //main
		executorService.execute(createJob(executorService)); //main
		executorService.execute(createJob(executorService)); //main
		Executors.newSingleThreadExecutor().execute(new Runnable() {

			public void run() {
				executorService.execute(createJob(executorService)); //pool thread
			}

		});
	}

	static class ThreadCreationInfoAwareExecutorInterceptor implements
			InvocationHandler {
		final ExecutorService executorService;

		/**
		 * @param executorService
		 */
		public ThreadCreationInfoAwareExecutorInterceptor(
				ExecutorService executorService) {
			super();
			this.executorService = executorService;
		}

		public Object invoke(final Object proxy, final Method method,
				final Object[] args) throws Throwable {
			if (args[0] instanceof ThreadCreationInfoAwareRunnable) {

				final ThreadCreationInfo threadCreationInfo = new ThreadCreationInfo();
				threadCreationInfo.setCreatorThread(new WeakReference<Thread>(
						Thread.currentThread()));
				threadCreationInfo.setCreatorThreadName(Thread.currentThread()
						.getName());
				threadCreationInfo.setStartTimeStackTraceOfCreatorThread(Thread
						.currentThread().getStackTrace());

				final ThreadCreationInfoAwareRunnable delegateeRunnable = (ThreadCreationInfoAwareRunnable) args[0];
				Runnable delegatingRunnable = new Runnable() {
					public void run() {

						delegateeRunnable
								.setThreadCreationInfo(threadCreationInfo);

						delegateeRunnable.run();
					}
				};

				args[0] = delegatingRunnable;
			}
			return method.invoke(this.executorService, args);
		}
	}

	static class ThreadCreationInfo {
		WeakReference<Thread> creatorThread;
		String creatorThreadName;
		StackTraceElement[] startTimeStackTraceOfCreatorThread;

		/**
		 * @return the creatorThread
		 */
		public WeakReference<Thread> getCreatorThread() {
			return creatorThread;
		}

		/**
		 * @param creatorThread
		 *            the creatorThread to set
		 */
		public void setCreatorThread(WeakReference<Thread> creatorThread) {
			this.creatorThread = creatorThread;
		}

		/**
		 * @return the creatorThreadName
		 */
		public String getCreatorThreadName() {
			return creatorThreadName;
		}

		/**
		 * @param creatorThreadName
		 *            the creatorThreadName to set
		 */
		public void setCreatorThreadName(String creatorThreadName) {
			this.creatorThreadName = creatorThreadName;
		}

		/**
		 * @return the startTimeStackTraceOfCreatorThread
		 */
		public StackTraceElement[] getStartTimeStackTraceOfCreatorThread() {
			return startTimeStackTraceOfCreatorThread;
		}

		/**
		 * @param startTimeStackTraceOfCreatorThread
		 *            the startTimeStackTraceOfCreatorThread to set
		 */
		public void setStartTimeStackTraceOfCreatorThread(
				StackTraceElement[] startTimeStackTraceOfCreatorThread) {
			this.startTimeStackTraceOfCreatorThread = startTimeStackTraceOfCreatorThread;
		}

	}

	static interface ThreadCreationInfoAwareRunnable extends Runnable {
		ThreadCreationInfo getThreadCreationInfo();

		void setThreadCreationInfo(ThreadCreationInfo threadCreationInfo);

	}

	/**
	 * @param executorService
	 * @return
	 */
	private static Runnable createJob(final ExecutorService executorService) {
		Runnable job = new ThreadCreationInfoAwareRunnable() {

			ThreadCreationInfo threadCreationInfo;

			public void run() {
				final String jobId = "" + hashCode();
				System.out.println("Executing job: " + jobId);

				Callable<String> task = createTaskFor(this);

				final List<Future<String>> futureTaskResults = new CopyOnWriteArrayList<Future<String>>();
				for (int i = 0; i < 3; i++) {
					futureTaskResults.add(executorService.submit(task));
				}

				Callable<List<String>> resultRetriever = createResultRetriever(
						jobId, futureTaskResults);

				Future<List<String>> futureResults = executorService
						.submit(resultRetriever);

				try {
					System.out.printf("finished job: %s with results: %s\n",
							jobId, futureResults.get());
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (ExecutionException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

			/**
			 * @return the creationThreadInfo
			 */
			public ThreadCreationInfo getThreadCreationInfo() {
				return threadCreationInfo;
			}

			/**
			 * @param threadCreationInfo
			 *            the creationThreadInfo to set
			 */
			public void setThreadCreationInfo(
					ThreadCreationInfo threadCreationInfo) {
				this.threadCreationInfo = threadCreationInfo;
			}
		};
		return job;
	}

	/**
	 * 
	 * @param jobId
	 * @param futureTaskResults
	 * @return
	 */
	private static Callable<List<String>> createResultRetriever(
			final String jobId, final List<Future<String>> futureTaskResults) {
		Callable<List<String>> resultRetriever = new Callable<List<String>>() {
			public List<String> call() throws Exception {
				List<String> results = new ArrayList<String>();
				while (!futureTaskResults.isEmpty()) {
					for (Future<String> futureTaskResult : futureTaskResults) {
						System.out
								.println("Checking for completion of tasks in job: "
										+ jobId);
						try {
							results.add(futureTaskResult.get(3,
									TimeUnit.SECONDS));
							futureTaskResults.remove(futureTaskResult);
						} catch (TimeoutException e) {
							System.out
									.printf(
											"Got time out while checking for completion of tasks in job: %s trying again...\n",
											jobId);
							continue;
							// e.printStackTrace();
						}
					}
				}
				return results;
			}
		};
		return resultRetriever;
	}

	/**
	 * 
	 * @param jobId
	 * @return
	 */
	private static Callable<String> createTaskFor(
			final ThreadCreationInfoAwareRunnable job) {
		Callable<String> task = new Callable<String>() {
			public String call() throws Exception {

				String creatorThreadName = job.getThreadCreationInfo().getCreatorThreadName();
				// ...

				System.out.println("call task -> creatorThread: "
						+ creatorThreadName);

				String taskId = String.valueOf(System.nanoTime());
				System.out.printf("Executing task %s within: %s\n", taskId, job
						.hashCode());
				TimeUnit.SECONDS.sleep((long) (Math.random() * 10 + 3));
				System.out.printf("Completed task: %s within: %s\n", taskId,
						job.hashCode());
				return taskId;
			}
		};
		return task;
	}
}
```

Gruß Tom


----------

