[concurrency-interest] thread cancellation prob

Tim Peierls tim at peierls.net
Sat Mar 28 12:06:20 EDT 2009


Some observations:

   - The use of a guarded static field to hold a singleton instance is
   technically OK, but the initialization on demand holder idiom is simpler.
   - Your test of status before starting the crawler thread is not atomic;
   this needs to be fixed. One way to write this kind of thing safely is using
   compare-and-set on an AtomicReference to an enum that holds the possible
   states of your object.
   - It's almost always better to separate the Thread from the Runnable --
   that way you can try out different execution policies later.
   - If your crawling involves blocking on long operations, consider making
   your crawl logic responsive to interruption.

Combining these ideas:

    public class Crawler implements Runnable {

        // Singleton

        public static Crawler getInstance() {
            return LazyHolder.instance;
        }

        private static class LazyHolder {
            private static final Crawler instance = new Crawler();
        }

        private Crawler() {}


        // Lifecycle

        public void start() {
            if (state.compareAndSet(State.NEW, State.STARTING)) {
                // If Crawler stops being a singleton, consider
                //
                //     Future<?> f = executorService.submit(this);
                //
                // and in stop(), instead of thread.interrupt(), use this:
                //
                //     f.cancel(true);

                (this.thread = new Thread(this)).start();
                state.set(State.RUNNING);
            }
        }

        public void stop() {
            if (state.compareAndSet(State.RUNNING, State.STOPPED)) {
                this.thread.interrupt();
                this.thread = null;
            }
        }

        public boolean isRunning() {
            State s = state.get();
            return s == State.STARTING || s == State.RUNNING;
        }


        // Runnable

        public void run() {
            while (isRunning()) {
                try {
                    crawl();
                } catch (InterruptedException e) {
                    break;
                }
            }
        }

        void crawl() throws InterruptedException {
            // Interrupt-responsive crawl logic
        }


        // Implementation

        enum State { NEW, STARTING, RUNNING, STOPPED }
        private final AtomicReference<State> state = new
AtomicReference<State>(State.NEW);
        private volatile Thread thread;
    }

--tim


On Sat, Mar 28, 2009 at 8:42 AM, Mubeen Shah <mubeenshah at gmail.com> wrote:

> Hello,
>
> Hope you all doing very well.
>
> I have a software (spring app) which is basically crawling the web pages,
> and I want to control that crawling execution (start, stop and check status)
> from other application using web-service, I need to expose three operations:
> start, stop and check. Please check the design below:
>
> I have one Crawler class extending the Thread class (Singleton):
>
> public class Crawler extends Thread {
>
> // ... some code here
>
> private static Crawler obj;
>
> private volatile boolean isRunning = false;
>
> private Crawler(){
>
> }
>
> public synchronized static Crawler getInstance(){
>
> if(obj == null){
>
> obj = new BusinessObject();
>
> }
>
> return obj;
>
> }
>
> public void run(){
>
> while(isRunning){
>
> // Crawling the webpages and storing html in DB.
>
> }
>
> }
>
> public void stopCrawler(){
>
> isRunning = false;
>
> }
>
> public boolean status(){
>
> return isRunning;
>
> }
>
> }
>
> }
>
> I have one web-service class extending ServletEndpointSupport (spring
> web-service):
>
> public class CrawlerManagerService extends ServletEndpointSupport {
>
> Crawler crawler = Crawler.getInstance();
>
> public String start(){
>
> if( !crawler.status() ){
>
> crawler.start();
>
> }
>
> return "RUNNING";
>
> }
>
> public String stop(){
>
> if(crawler.status()){
>
> crawler.stopCrawler();
>
> }
>
> return "NOT-RUNNING";
>
> }
>
> public String status(){
>
> return ( ( crawler.status )?"RUNNING":"NOT-RUNNING");
>
> }
>
> }
>
>
>
> I exposed 3 methods:
>
> start(); // to start the process in thread (i just want a single thread)
> stop(); // to stop the thread
> status(); // check the current status of that thread
>
> But everytime i am calling this webservice its creating a new thread and
> starting service. for now i did one workaround to fix this issue:
>
> I am searching all running threads:
>
> Thread[] allSystemThreads; // suppose i have all running threads in system
>
> den:
>
> Crawler crl = null;
>
> for(Thread t : allSystemThreads){
>
> if(t instanceof Crawler){
>
> crl = (Crawler) t;
>
> break;
>
> }
>
> }
>
> if(crl != null){
>
> // i found the thread now i can start, stop and check status here
>
> }
>
>
>
> but i am not sure if its a good way to search for all threads and do the
> required operation. can you please advise any possiblity in
> java.util.concurrent package to utilize it in a standard way? so that i dont
> need to go deeply to manage the threads. Please help me.
>
> Looking forward to hear from you.
>
> Regards,
> Mubeen Shah
>
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20090328/df1b2b42/attachment.html>


More information about the Concurrency-interest mailing list