0

谁能告诉我一种在允许启动下一个任务之前强制完成 java 中的一个任务的方法?具体来说,我想编辑下面的代码,以便在调用下一个标记的两行代码之前完全完成前标记的两行代码。

protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {
      String idString = req.getParameter("id");
      Long id = new Long(idString);
//complete the actions specified on next two lines
      School school = new SchoolDAO().findSchool(id);
      req.setAttribute("school", school);
//before even starting the actions specified on the next two lines
      List<CourseSummary> coursesummaries = new CourseSummaryDAO().findAllcsum(id);
      req.setAttribute("coursesummaries", coursesummaries);

      jsp.forward(req, resp);
}  

编辑:

为了更好地理解费尔南多的建议,我将 SchoolDAO 的一些相关部分包括如下:

public class SchoolDAO extends DataAccessObject{
    public School findSchool(Long id) {
        ResultSet rs = null;
        PreparedStatement statement = null;
        Connection connection = null;
        try {
            connection = getConnection();
            String sql = "select * from schoolprog where id=?";
            statement = connection.prepareStatement(sql);
            statement.setLong(1, id.longValue());
            rs = statement.executeQuery();
            if (!rs.next()) {return null;}
            return readSchool(rs);
         }
         catch (SQLException e) {throw new RuntimeException(e);}
         finally {close(rs, statement, connection);}
      }
      private School readSchool(ResultSet rs) throws SQLException {
          Long id = new Long(rs.getLong("id"));
          String spname = rs.getString("spname");
          String spurl = rs.getString("spurl");
          School school = new School();
          school.setId(id);
          school.setName(spname);
          school.setUrl(spurl);
          return school;
      }
}  

同样,CourseSummaryDAO 包含:

public class CourseSummaryDAO extends DataAccessObject{
    public List<CourseSummary> findAllcsum(Long sid) {
        LinkedList<CourseSummary> coursesummaries = new LinkedList<CourseSummary>();
        ResultSet rs = null;
        PreparedStatement statement = null;
        Connection connection = null;
        try {
            connection = getConnection(); //this is the line throwing null pointer error
      String sql = "select * from coursetotals where spid=?";
            statement = connection.prepareStatement(sql);
            statement.setLong(1, sid);
            rs = statement.executeQuery();
      //for every row, call read method to extract column 
            //values and place them in a coursesummary instance
            while (rs.next()) {
                CourseSummary coursesummary = readcsum("findAll", rs);
                coursesummaries.add(coursesummary);
            }
            return coursesummaries;
         }
         catch (SQLException e) {throw new RuntimeException(e);} 
         finally {close(rs, statement, connection);}
     }

程序中断的行是:

connection = getConnection(); //
4

3 回答 3

2

如果您有两个任务应该连续执行(即一个在下一个开始之前完成),那么最好的答案是同步执行它们。例如,假设task1()task2()是任务:

// Wrong way:
Runnable r1 = new Runnable(){
    public void run() {
        task1();
    }};
Runnable r2 = new Runnable(){
    public void run() {
        // Wait for r1 to finish task1 ... somehow
        task2();
    }};

// Right way:
Runnable r = new Runnable(){
    public void run() {
        task1();
        task2();
    }};

在您的情况下,看起来doGet调用只能在获得两个任务的结果时返回。所以这表明在这种情况下你根本不应该使用线程。只需在请求线程task1()task2()按顺序调用 ...。


编辑

查看doGet您随后添加的方法和两个类,看起来处理已经是顺序/串行的。也就是说,第一个“任务”在第二个“任务”开始之前结束。

getConnection()投掷的问题NullPointerException(很可能)与异步无关。getConnection()但是,如果没有看到代码和完整的堆栈跟踪,我无法确定这一点。

于 2013-08-10T03:17:10.460 回答
1

在 Java 中,一切通常都是按顺序执行的,这意味着给定的代码行将在下一行开始执行任何操作之前完全执行完。这条规则的例外是线程开始发挥作用。线程允许同时执行多个代码块。因为你没有在你的程序中使用任何线程(你会知道你是否使用过,别担心),所以可以保证前两行代码将在接下来的两行开始执行之前完成。

因此,您的问题似乎不是您的代码“乱序”运行。getConnection()如果这是抛出 NPE 的原因,那么您的错误很可能在方法中的某个地方。

于 2013-08-10T03:20:03.350 回答
0

这是一个示例(有关详细信息,请参阅Java 线程等待值

import java.util.concurrent.CountDownLatch;

class MyTask implements Runnable
{

    CountDownLatch signal;

    public MyTask(CountDownLatch signal)
    {
        this.signal = signal;
    }

    public void run()
    {
        System.out.println("starting task");
        for (int i = 0; i < 10000000; i++)
            Math.random();

        //call when the task is done
        signal.countDown();
    }
}


public class Program
{
    public static void main(String[] args) {
        int workers = 1;
        CountDownLatch signal = new CountDownLatch(workers);

        new Thread(new MyTask(signal)).start();

         try {
                // Waits for all the works to finish ( only 1 in this case)
                signal.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("task is done");
        }

}

这只是一个建议,也许有更好的设计:

import java.util.concurrent.CountDownLatch;

public class SchoolDAO extends DataAccessObject implements Runnable {

    Long id;
    CountDownLatch signal;
    School searchResult;

    public SchoolDAO(Long id, CountDownLatch signal)
    {
        this.id = id;
        this.signal = signal;
    }

    public void run()
    {
       searchResult = findSchool(id);
       signal.countDown();
    }

    // the other methods didn't change
}  

现在你可以在 doGet() 中调用它:

CountDownLatch signal = new CountDownLatch(1);
SchoolDAO dao = new SchoolDAO(id, signal);

new Thread(dao).start();
try {        
      signal.await();
    } catch (InterruptedException e) 
    {
      e.printStackTrace();
    }
 School result = dao.searchResult;
于 2013-08-10T02:24:46.327 回答