Используете ли Вы Тестирование системы Команды или NUnit, лучшая практика должна создать отдельную Библиотеку классов для Ваших тестов. Просто добавление App.config к Вашему Тестовому проекту будет автоматически скопировано в Вашу папку мусорного ведра, когда Вы скомпилируете .
, Если бы Ваш код уверен в определенных тестах конфигурации, самый первый тест, я записал бы, проверяет это, конфигурационный файл доступен ( так, чтобы я знал, что я весьма нормален ):
<configuration>
<appSettings>
<add key="TestValue" value="true" />
</appSettings>
</configuration>
И тест:
[TestFixture]
public class GeneralFixture
{
[Test]
public void VerifyAppDomainHasConfigurationSettings()
{
string value = ConfigurationManager.AppSettings["TestValue"];
Assert.IsFalse(String.IsNullOrEmpty(value), "No App.Config found.");
}
}
Идеально, необходимо писать код, таким образом, что объекты конфигурации передаются в классы. Это не только разделяет Вас от проблемы конфигурационного файла, но и она также позволяет Вам тестам записи на различные сценарии конфигурации.
public class MyObject
{
public void Configure(MyConfigurationObject config)
{
_enabled = config.Enabled;
}
public string Foo()
{
if (_enabled)
{
return "foo!";
}
return String.Empty;
}
private bool _enabled;
}
[TestFixture]
public class MyObjectTestFixture
{
[Test]
public void CanInitializeWithProperConfig()
{
MyConfigurationObject config = new MyConfigurationObject();
config.Enabled = true;
MyObject myObj = new MyObject();
myObj.Configure(config);
Assert.AreEqual("foo!", myObj.Foo());
}
}
Вы помещаете все потоки в массив, запускаете их все, а затем получаете цикл
for(i = 0; i < threads.length; i++)
threads[i].join();
Каждое соединение будет блокироваться до тех пор, пока соответствующий поток не завершится. Потоки могут завершаться в другом порядке, чем вы присоединяетесь к ним, но это не проблема: когда цикл завершается, все потоки завершаются.
Это можно сделать с помощью объекта «ThreadGroup» и его параметра activeCount :
Это будет комментарий, но я пока не могу комментировать.
Мартин K , мне любопытно, как бы вы использовали ThreadGroup
. Вы делали это раньше?
Я вижу, что выше вы предлагаете проверить activeCount
- оставив в стороне озабоченность Мартина v Лёвиса по поводу опроса на данный момент, у меня есть еще одно беспокойство с activeCount
.
Предостережение: я не пробовал использовать это, поэтому я не эксперт в этом вопросе, но, согласно javadocs , он возвращает ] оценка количества активных потоков.
Лично мне было бы неприятно пытаться построить систему на основе оценки. У вас есть еще одна мысль, как это сделать, или я неправильно читаю javadoc?
В зависимости от ваших потребностей вы можете также захотеть проверить классы CountDownLatch и CyclicBarrier в пакете java.util.concurrent. Они могут быть полезны, если вы хотите, чтобы ваши потоки ожидали друг друга, или если вы хотите более детальный контроль над тем, как ваши потоки выполняются (например, ожидая в своем внутреннем исполнении, чтобы другой поток установил какое-то состояние). Вы также можете использовать CountDownLatch, чтобы сигнализировать всем вашим потокам о запуске одновременно, вместо того, чтобы запускать их один за другим при повторении цикла. В стандартной документации API есть пример этого, а также использование другого CountDownLatch для ожидания завершения выполнения всеми потоками.
Если вы составите список потоков, вы можете перебрать их и выполнить .join () для каждого, и ваш цикл завершится, когда все потоки будут иметь. Но я не пробовал.
http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#join ()
Один из способов - создать Список
из Thread
s, создать и запустить каждый поток, добавляя его в список. Как только все будет запущено, вернитесь к списку и вызовите join ()
для каждого из них. Неважно, в каком порядке завершаются выполнение потоков, все, что вам нужно знать, это то, что к тому времени, когда завершится выполнение второго цикла, все потоки будут завершены.
Лучше использовать ExecutorService и связанных с ним методов:
List<Callable> callables = ... // assemble list of Callables here
// Like Runnable but can return a value
ExecutorService execSvc = Executors.newCachedThreadPool();
List<Future<?>> results = execSvc.invokeAll(callables);
// Note: You may not care about the return values, in which case don't
// bother saving them
Использование ExecutorService (и всех новых вещей из Java 5 утилит параллелизма ) невероятно гибко, и приведенный выше пример едва ли касается поверхности.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class DoSomethingInAThread implements Runnable
{
public static void main(String[] args) throws ExecutionException, InterruptedException
{
//limit the number of actual threads
int poolSize = 10;
ExecutorService service = Executors.newFixedThreadPool(poolSize);
List<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();
for (int n = 0; n < 1000; n++)
{
Future f = service.submit(new DoSomethingInAThread());
futures.add(f);
}
// wait for all tasks to complete before continuing
for (Future<Runnable> f : futures)
{
f.get();
}
//shut down the executor service so that this thread can exit
service.shutdownNow();
}
public void run()
{
// do something here
}
}
Полностью избегайте класса Thread и вместо этого используйте более высокие абстракции, представленные в java.util.concurrent
Класс ExecutorService предоставляет метод invokeAll , который, кажется, делает именно то, что вы хотите.