2013-05-30 53 views
10

因此,我有一項服務設置爲從用戶上傳的文件導入大量數據。我希望用戶能夠在文件正在處理時繼續在網站上工作。我通過創建一個線程來完成此任務。管理Grails服務中的線程

Thread.start { 
//work done here 
} 

現在問題出現了,我不想讓多個線程同時運行。這是我試過的:

class SomeService { 

Thread thread = new Thread() 

def serviceMethod() { 
    if (!thread?.isAlive()) { 
    thread.start { 
     //Do work here 
    } 
    } 
} 

} 

但是,這是行不通的。 thread.isAlive()總是返回false。有關我如何完成此任何想法?

回答

15

我會考慮使用Executor來代替。

import java.util.concurrent.* 
import javax.annotation.* 

class SomeService { 

ExecutorService executor = Executors.newSingleThreadExecutor() 

def serviceMethod() { 
    executor.execute { 
     //Do work here 
    } 
} 


@PreDestroy 
void shutdown() { 
    executor.shutdownNow() 
} 

} 

使用newSingleThreadExecutor將確保任務一個接一個地執行。如果後臺任務已在運行,則下一個任務將排隊並在運行任務完成時啓動(serviceMethod本身仍將立即返回)。

如果您的「在此工作」涉及GORM數據庫訪問,您可能希望考慮executor plugin,因爲該插件將爲您的後臺任務設置適當的持久化上下文(例如Hibernate會話)。

+0

它涉及GORM。我真的不喜歡爲此僅安裝一個插件。我可以繞過使用嗎? –

+0

@JamesKleeh使用'withTransaction'應該可以做到這一點(至少如果你在休眠狀態下,我不會說mongo),但執行器插件的重量非常輕,所以我不會無視它。 –

+0

@JamesKleeh,你可以在源代碼https://github.com/basejump/grails-executor/tree/master/src/groovy/grails/plugin/executor中獲取你需要的相關部分。我只是使用插件,如果我是你,爲了避免處理潛在的持久性問題... – rimero

2

另一種方法是使用Spring的@Async註釋。

以下內容添加到resources.groovy

beans = { 
    xmlns task:"http://www.springframework.org/schema/task" 
    task.'annotation-driven'('proxy-target-class':true, 'mode':'proxy') 
} 

你現在@Async標註任何服務方法異步運行,例如

@Async 
def reallyLongRunningProcess() { 
    //do some stuff that takes ages 
} 

如果你只想要一個線程上同時運行的進口,你可以做這樣的事情 -

class MyService { 
    boolean longProcessRunning = false 

    @Async 
    def reallyLongRunningProcess() { 
     if (longProcessRunning) return 

     try { 
      longProcessRunning = true 
      //do some stuff that takes ages 
     } finally { 
      longProcessRunning = false 
     } 
    } 
} 
+0

我很欣賞這個答案,但是我可以用我的方式設置一個帶有標誌的變量。我只是不想這樣做。 –