Java: Threadpoolexecutor - использовать список заданий для отправки заданий? - PullRequest
0 голосов
/ 27 октября 2018

Следующий код - Customer и jobManager. У клиентов есть имя, адрес и баланс счета. Рабочие места - это денежные переводы от одного клиента другому. Это программа обучения Threadpoolexecutor. Следующая версия работает, и я отправляю задания по одному.

customer.java

public class customer {

    private String name;
    private String adress;
    private Double accountBalance;

    public customer(String name, String adress, Double accountBalance)
    {
        this.name = name;
        this.adress = adress;
        this.accountBalance = accountBalance;
    }

    public String getName() { return name; }

    public String getAdress()
    {
        return adress;
    }

    public Double getAccountBalance(){return accountBalance;}

    public void setAccountBalance(double accountBalance){this.accountBalance=accountBalance;}

    @Override
    public String toString(){

        return "[" + name+"; " +adress+"; "+accountBalance+"]";
    }
}

customerOrganizer.java

import java.util.ArrayList;
import java.util.List;

public class customerOrganizer {

    private static final customerOrganizer myJobOrganizer = new customerOrganizer();

    public static customerOrganizer getJobOrganizer(){
        return myJobOrganizer;
    }

    private List<customer> customerList = new ArrayList<customer>();

    public void add_customer(customer kunde)
    {
        this.customerList.add(kunde);
    }

    public Iterable<customer> all_customers()
    {
        return this.customerList;
    }

    public static customerOrganizer getInstance()
    {
        return myJobOrganizer;
    }

}

job.java

public class job implements Runnable {
    private customer kunde1;
    private customer kunde2;
    private Double transfer;

    public job(customer kunde1, customer kunde2, Double transfer) {
        this.kunde1 = kunde1;
        this.kunde2 = kunde2;
        this.transfer = transfer;
    }

    @Override
    public String toString(){

        return "[" + kunde1+"; " +kunde2+"; "+transfer+"]";
    }

    public void run() {

        System.out.println("Starting transfer");

        Double geber = this.kunde1.getAccountBalance();
        Double nehmer = this.kunde2.getAccountBalance();

        Double geberNeu = geber - this.transfer;
        this.kunde1.setAccountBalance(geberNeu);

        Double nehmerNeu = nehmer + this.transfer;
        this.kunde2.setAccountBalance(nehmerNeu);
        System.out.println("Transfer done");
    }
}

jobOrganizer.java

public class jobOrganizer {

    private static final jobOrganizer myJobOrganizer = new jobOrganizer();

    public static jobOrganizer getMyJobOrganizer() {
        return myJobOrganizer;
    }

    private List<job> jobList = new ArrayList<job>();

    public int getAmount(){ return jobList.size();}

    public void add_job(job newJob) {
        this.jobList.add(newJob);
    }

    public Iterable<job> all_jobs() {
        return this.jobList;
    }

    public static jobOrganizer getInstance() {
        return myJobOrganizer;
    }

}

Main.java

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

    public static void main(String[] args) {
        customerOrganizer myCustomerOrganizer = new customerOrganizer();
        jobOrganizer myJobOrganizer= new jobOrganizer();

        customer mueller = new customer("Tim Mueller", "Strasse 1", 1077.00);
        customer john = new customer("John Doe", "Strasse 2",503.00);
        customer meier = new customer("John Meier", "Strasse 3", 8500.50);
        customer wurst = new customer("Hans Wurst", "Strasse 4", 1000.00);

        myCustomerOrganizer.add_customer(mueller);
        myCustomerOrganizer.add_customer(john);
        myCustomerOrganizer.add_customer(meier);
        myCustomerOrganizer.add_customer(wurst);

        job transfer1= new job(meier,wurst,500.50);
        job transfer2= new job(mueller,john,77.00);

        myJobOrganizer.add_job(transfer1);
        myJobOrganizer.add_job(transfer2);

        // this works:
        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.submit(transfer1);
        executor.submit(transfer2);
        executor.shutdown();


    }}

Итак, у меня есть список вакансий, и у меня есть идея, что я должен его использовать. Вместо того, чтобы отправлять вакансии по одному, я хотел бы представить их на основе списка вакансий. Я подумал о чем-то вроде этого для начала:

 int threads = myJobOrganizer.getAmount();
        ExecutorService executor = Executors.newFixedThreadPool(threads);
        for (int i = 0; i <threads+1; i++){
            //submit jobs? execute?
        }

Кроме того, myJobOrganizer должен был бы реализовать Runnable? Я также видел, что решения примерно такие:

for(condition){

        executor.execute(new Runnable() {

            @Override
            public void run() {
              submit the jobs?
                }
            }}

Но я действительно не знаю, как это сделать. По сути, мне не хватает того, как правильно извлечь задания из моего списка вакансий, чтобы я мог отправить их в службу исполнителя>. <</p>

Обновление, касающееся безопасности потоков

Итак, я перешел по ссылке, предоставленной Rab, я использовал CompletionService. Последняя часть Main.java теперь выглядит так:

int threads = myJobOrganizer.getAmount();

System.out.println(myCustomerOrganizer.all_customers().toString());
// executor service   
ExecutorService executor = Executors.newFixedThreadPool(threads);
// completion service is applied on executor
CompletionService service = new ExecutorCompletionService(executor);

for(Callable<Job> myJob : myJobOrganizer.all_jobs()){
    service.submit(myJob);
}
executor.shutdown();
// pause the main for control printout -> not nice yet, I am working on 
// joining threads
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
// control print
System.out.println(myCustomerOrganizer.all_customers().toString());

Пожалуйста, обратите внимание, что это изменение предназначено для завершения записи, но все еще неправильно (к сожалению). Предоставленные ответы связаны с оригинальным вопросом и НЕ касаются безопасности потоков

Спасибо за ваше время и усилия!

Ответы [ 2 ]

0 голосов
/ 27 октября 2018

Вы можете сделать это, используя Stream, если вы не хотите использовать циклы.если вы используете версию Java, большую или равную 8, вот пример

    myJobList
            .stream()
            .forEach(e -> executor.execute(() -> {
        //submit the jobs
    }));

или

    myJobOrganizer.all_jobs()
            .stream()
            .forEach(e -> executor.submit(e));

Вы можете просто отправить свой список, используя executor.invokeAll(myJobList), если вы действительно этого не делаетехотите цикл

0 голосов
/ 27 октября 2018

ExecutorService обрабатывает, как задачи распределяются между работниками.Все, что вам нужно сделать, это передать задания по очереди.

for (job jobObj : myJobOrganizer.all_jobs()) 
    executor.submit(jobObj);

Обратите внимание, что sumbit возвращает Future<?>, который используется для отслеживания того, завершены ли ваши задачи или если они ошиблись (а также результат задачи, но runnable не имеет результатов).Если вы заботитесь об этих вещах, вам нужно собрать их в какой-то контейнер, например List.


Если вы измените job на Callable<Void>, отправка будетгораздо проще сделать.Callable - это своего рода расширение Runnable, которое позволяет заданию давать результат после завершения.Поскольку ваш перевод не дал результатов, использование java.lang.Void в качестве типа заполнителя для универсального параметра было бы хорошо.

Теперь достаточно сделать executor.invokeAll(myJobOrganizer.all_jobs()).Это сэкономило бы несколько переключений контекста, немного ускорив процесс.(на самом деле очень важно, потому что все ваши задачи очень малы)


Кстати, вы должны знать, что для одновременного доступа требуется правильная синхронизация, которой у вас нет.Ваши учетные записи могут оказаться в неправильном состоянии, если на разных работах задействована одна и та же учетная запись.Мы также обычно называем классы в LargeCamelCase, а имена методов - в smallCamelCase.

...