Потоки Java: указание того, что должно выполняться в функции запуска - PullRequest
1 голос
/ 21 января 2009

У меня есть класс DBAdmin, который подключается к базе данных, а затем некоторые другие классы, такие как Article, Category и т. Д., Которые выполняют определенные запросы к базе данных.

Я использую эти классы в приложении Swing для создания своего рода небольшого приложения CMS для интрасети.

Теперь класс Category имеет несколько static методов, таких как addCategory, editCategory и т. Д., Например:

public class Category implements Runnable {

    public void run () {
        //Code that will be executed in a separate thread, from the Runnable Interface
    }

    public static int addCategory(Category cat) {
        DBAdmin db = DBAdmin.getInstance();
        db.connectDB();
        //rest of the code that creates sql statement and so on...
    }

    //Other static edit and delete methods that will be called from outside
}

P.S. DBAdmin - это класс Singleton, а метод getInstance возвращает самовоспроизводимый экземпляр.

Теперь я пытаюсь выполнить действия с базой данных в отдельном потоке от приложения, и мне удалось выполнить несколько тестов, которые выполняются в методе run, когда Thread started.

Но проблема в том, что я не могу указать, какой метод следует запускать в методе run при запуске потока.

В том смысле, что когда, например, addCategory вызывается извне, метод run должен вызывать метод addCategory внутри него.

Есть ли способ передать функцию в качестве параметра обратного вызова методу run из метода addCategory, чтобы он знал, какая функция должна быть вызвана в нем при запуске нового потока? Или есть совершенно другой способ добиться того, что я пытаюсь сделать?

P.S. На данный момент я "довольно" новичок в Java, особенно в многопоточности, поэтому я могу что-то здесь упустить.

Ответы [ 2 ]

7 голосов
/ 21 января 2009

Звучит так, как будто вы хотите создать единый поток, который обеспечивает весь доступ к базе данных для всей программы, и в этом случае вам не следует передавать данные методу run. Потому что, когда у вас есть один поток, все, что он делает, это вызывает один метод run один раз, когда он запускается, и этот метод run просто продолжает выполняться до тех пор, пока не вернется или поток не будет принудительно завершен. Чтобы сделать это, нужно иметь синхронизированную очередь, скажем, в вашем классе DBAdmin. Затем такие методы, как addCategory, подготовят свои операторы и добавят их в эту общую очередь. Один поток базы данных обрабатывает операторы в очереди по одному, а когда оператор завершается, он уведомляет поток, который добавил его в очередь. Фактически, Java (по крайней мере, в последних версиях) включает в себя набор классов, которые будут делать именно это для вас; они называются исполнителями, и их можно найти в пакете java.util.concurrent. В частности, посмотрите на метод java.util.concurrent.Executors.newSingleThreadExecutor (), который я бы использовал в такой ситуации.

class SQLQueryCallable implements Callable<SQLResultSet> {
    private String query;
    public SQLQueryCallable(String query) {
        this.query = query;
    }
    public SQLResultSet Call() throws Exception {
        // execute query
        return results;
    }
}
ExecutorService ex = Executors.newSingleThreadExecutor();

// in DBAdmin somewhere:
    public SQLResultSet runQuery(String query) {
        Future<SQLResultSet> f = ex.submit(new SQLQueryCallable(query));
        return f.get(); // this waits for the query to complete
    }

Если я неправильно прочитал ваш вопрос, и вы действительно хотите, чтобы каждый запрос к базе данных выполнялся в своем собственном потоке, то я бы предложил создать класс с именем что-то вроде SQLQuery, который реализует Runnable (или расширяет Thread) - фактически, Вы могли бы даже рассмотреть использование java.util.concurrent.Callable, которое позволяет вам возвращать значение из его метода call () (который похож на run ()). Конструктор класса должен принимать оператор SQL в качестве параметра, а его метод run должен выполнять всю работу по выполнению этого оператора. Затем, если вы использовали Callable, вы можете вернуть результат оператора, или, если вы использовали Runnable, вы можете сохранить его в каком-то общедоступном месте. Это простой ответ на вопрос о том, как передавать данные в метод run (): используйте конструктор класса.

class SQLQueryRunnable implements Runnable {
    private String query;
    public SQLQueryRunnable(String query) {
        this.query = query;
    }
    public void run() {
        // execute query
    }
}

P.S. Многопоточность - это сложная вещь, к которой нужно привыкнуть, но Java - хороший язык для этого (на мой взгляд).

0 голосов
/ 21 января 2009

Как указал Адил, вы, кажется, смешиваете данные и операции в одном классе. Но если вы хотите придерживаться этого, вы можете добавить поле категории в Category, которое можно использовать в переключателе (или некоторых других) в методе run.

Action.java:

enum Action {ADD, EDIT, DELETE}

в DbAdmin:

Category c = new Category(Action.ADD, /* other category parameter */);
c.start();

Category.run:

switch (_action) {
case ADD: addCategory(this);  // or make addCategory instance method
.....
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...