Вот другой подход - инкапсуляция; таким образом, Ваш код мог быть столь же простым как:
Forker p = new Forker();
foreach (var obj in collection)
{
var tmp = obj;
p.Fork(delegate { DoSomeWork(tmp); });
}
p.Join();
, Где Forker
класс дан ниже (я скучал на поезде;-p)... снова, это избегает объектов ОС, но оборачивает вещи вполне аккуратно (IMO):
using System;
using System.Threading;
/// <summary>Event arguments representing the completion of a parallel action.</summary>
public class ParallelEventArgs : EventArgs
{
private readonly object state;
private readonly Exception exception;
internal ParallelEventArgs(object state, Exception exception)
{
this.state = state;
this.exception = exception;
}
/// <summary>The opaque state object that identifies the action (null otherwise).</summary>
public object State { get { return state; } }
/// <summary>The exception thrown by the parallel action, or null if it completed without exception.</summary>
public Exception Exception { get { return exception; } }
}
/// <summary>Provides a caller-friendly wrapper around parallel actions.</summary>
public sealed class Forker
{
int running;
private readonly object joinLock = new object(), eventLock = new object();
/// <summary>Raised when all operations have completed.</summary>
public event EventHandler AllComplete
{
add { lock (eventLock) { allComplete += value; } }
remove { lock (eventLock) { allComplete -= value; } }
}
private EventHandler allComplete;
/// <summary>Raised when each operation completes.</summary>
public event EventHandler<ParallelEventArgs> ItemComplete
{
add { lock (eventLock) { itemComplete += value; } }
remove { lock (eventLock) { itemComplete -= value; } }
}
private EventHandler<ParallelEventArgs> itemComplete;
private void OnItemComplete(object state, Exception exception)
{
EventHandler<ParallelEventArgs> itemHandler = itemComplete; // don't need to lock
if (itemHandler != null) itemHandler(this, new ParallelEventArgs(state, exception));
if (Interlocked.Decrement(ref running) == 0)
{
EventHandler allHandler = allComplete; // don't need to lock
if (allHandler != null) allHandler(this, EventArgs.Empty);
lock (joinLock)
{
Monitor.PulseAll(joinLock);
}
}
}
/// <summary>Adds a callback to invoke when each operation completes.</summary>
/// <returns>Current instance (for fluent API).</returns>
public Forker OnItemComplete(EventHandler<ParallelEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException("handler");
ItemComplete += handler;
return this;
}
/// <summary>Adds a callback to invoke when all operations are complete.</summary>
/// <returns>Current instance (for fluent API).</returns>
public Forker OnAllComplete(EventHandler handler)
{
if (handler == null) throw new ArgumentNullException("handler");
AllComplete += handler;
return this;
}
/// <summary>Waits for all operations to complete.</summary>
public void Join()
{
Join(-1);
}
/// <summary>Waits (with timeout) for all operations to complete.</summary>
/// <returns>Whether all operations had completed before the timeout.</returns>
public bool Join(int millisecondsTimeout)
{
lock (joinLock)
{
if (CountRunning() == 0) return true;
Thread.SpinWait(1); // try our luck...
return (CountRunning() == 0) ||
Monitor.Wait(joinLock, millisecondsTimeout);
}
}
/// <summary>Indicates the number of incomplete operations.</summary>
/// <returns>The number of incomplete operations.</returns>
public int CountRunning()
{
return Interlocked.CompareExchange(ref running, 0, 0);
}
/// <summary>Enqueues an operation.</summary>
/// <param name="action">The operation to perform.</param>
/// <returns>The current instance (for fluent API).</returns>
public Forker Fork(ThreadStart action) { return Fork(action, null); }
/// <summary>Enqueues an operation.</summary>
/// <param name="action">The operation to perform.</param>
/// <param name="state">An opaque object, allowing the caller to identify operations.</param>
/// <returns>The current instance (for fluent API).</returns>
public Forker Fork(ThreadStart action, object state)
{
if (action == null) throw new ArgumentNullException("action");
Interlocked.Increment(ref running);
ThreadPool.QueueUserWorkItem(delegate
{
Exception exception = null;
try { action(); }
catch (Exception ex) { exception = ex;}
OnItemComplete(state, exception);
});
return this;
}
}
обычно это что-то, что вы изменили недавно, сначала ваш пример кода: если файл не существует и не создается новый файл - вы пытаетесь что-то закодировать - что это?
Тогда просмотрите список каталогов, чтобы узнать, существует ли он на самом деле, и выполните println / toString () для объекта файла и getMessage () для исключения, а также трассировку стека печати.
Затем снова начните с нуля и С самого начала учитывайте каждый шаг, который вы используете, чтобы добраться сюда. Вероятно, вы застряли где-то там, осмысляя код (потому что он работал) - вы просто прослеживаете каждый шаг в деталях, и вы его найдете.
попытайтесь убедиться, что родительский каталог существует с:
file.getParentFile().mkdirs()
Согласно [java docs] ( http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html#createNewFile () ) createNewFile
автоматически создаст для вас новый файл.
Атомарно создает новый пустой файл, названный этим абстрактным путем, тогда и только тогда, когда файл с таким именем еще не существует.
Учитывая, что createNewFile
является атомарным и не перезаписывает существующий файл, вы можете переписать свой код как
try {
if(!file.createNewFile()) {
System.out.println("File already exists");
}
} catch (IOException ex) {
System.out.println(ex);
}
. Это может упростить обнаружение любых потенциальных проблем с потоками, условий гонки и т.д.
Я думаю, что исключение, которое вы получаете, вероятно, является результатом проверки файлов атомарным методом file.createNewFile ()
. Метод не может проверить, существует ли файл, потому что некоторые из родительских каталогов не существуют или у вас нет разрешений для доступа к ним. Я бы предложил следующее:
if (file.getParentFile() != null && !file.getParentFile().mkDirs()) {
// handle permission problems here
}
// either no parent directories there or we have created missing directories
if (file.createNewFile() || file.isFile()) {
// ready to write your content
} else {
// handle directory here
}
Если принять во внимание параллелизм, все эти проверки бесполезны, потому что в любом случае какой-то другой поток может создавать, удалять или делать что-нибудь еще с вашим файлом. В этом случае вы должны использовать блокировку файлов, чего я бы не предлагал делать;)
Вы определенно получаете это исключение «Система не может найти указанный путь»
Просто напечатайте «file.getAbsoluteFile ()», это даст вам знать, какой файл вы хотите создать.
Это исключение возникает, если каталог, в котором вы создаете файл, не существует .
Хм. Похоже, что самый простой способ получить то, что я хочу на стороне Java приложения, - использовать Servlet.getServletConfig ().
getInitParameter (parameterName)
например, getInitParameter ("myApp.connectionString");
Но я не знаю, где это установить. В документации Tomcat рассказывается о различных перестановках context.xml, но я хочу убедиться, что этот параметр влияет только на мой сервлет, а не на другие. Я также не хочу размещать его в моем файле .war, чтобы я мог сохранить этот параметр независимо от приложений (например, если я устанавливаю обновление).
Обновление: Я понял это, ключ / параметры значения, доступные для ServletContext.getInitParameter () , перейдите сюда (или можете перейти сюда) в $ {CATALINA_HOME} /conf/server.xml:
<Server port=... >
...
<Service name="Catalina" ...>
<Engine name="Catalina" ...>
...
<Host name="localhost" ...>
<Context path="/myWarFile">
<Parameter name="foo" value="123" />
<Parameter name="bar" value="456" />
...
</Context>
</Host>
</Engine>
</Service>
</Server>
Это устанавливает два параметра, "
Это может быть проблема многопоточности (совместная проверка и создание не атомарны: ! File.exists () &&! File.createNewFile ()
) или "файл" уже является каталогом .
Попробуйте ( file.isFile ()
):
if (file.exists() && !file.isFile()){
//handle directory is there
}else if(!file.createNewFile()) {
//as before
}