确保一个任务在另一个任务在java中启动之前完成

时间:2013-08-10 01:54:13

标签: java jsp servlets

任何人都可以告诉我在下一个任务允许启动之前强制执行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);
}  

编辑:

为了更好地理解费尔南多的建议,我将学校的一些相关部分包括在内:

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(); //

3 个答案:

答案 0 :(得分: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()完成堆栈跟踪的代码,我就无法确定。

答案 1 :(得分:1)

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

所以,你的问题似乎并不是你的代码“乱序”运行。你的错误很可能是在getConnection()方法中的某个地方,如果这就是投掷NPE的那个。

答案 2 :(得分:0)

以下是一个示例(有关详细信息,请参阅Java Threads waiting value

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;