Avatar billede fredand Forsker
19. april 2004 - 14:14 Der er 15 kommentarer og
3 løsninger

Threads, which way is the best?

Hello!

I would like to get some comment around this code about Threads.

I use to build apps with Threads like pattern Thread1. I could also build it like code ex Thread2, but I'm pretty sure that it is prefferable to do it like Thread1 but I can't remeber why! So if any one could help me with some comment which pattern is the best.

Best regards
Fredrik

BTW please give answers so I can avard all of you!



//Pattern 1

import java.awt.*;
import java.applet.*;

public class Thread1 implements Runnable
{
    Thread thread;
    boolean run;
    int state = 0;

    public static void main(String[] args)
    {
        new Thread1();
    }
   
    public Thread1()
    {
        start();
    }

    public void run()
    {
        while(run)
        {
            try
            {
                switch(state)
                {
                    case 0:
                        thread.sleep(500);
                        state = 1;
                        break;
                    case 1:
                        doSomeStuff();
                        state = 0;
                    break;
                }
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    public void start()
    {
        run = true;
        if(thread == null)
        {
            thread = new Thread(this);
        }
        thread.start();
    }

    public void stop()
    {
        run = false;
        thread = null;
    }

    public void setState(int s)
    {
        state = s;
    }

    private void doSomeStuff() throws InterruptedException
    {
        System.out.println("Hello from thread 1");
    }
}

//Pattern 2

public class Thread2
{
    boolean run = true;
    int state = 0;

    public static void main(String[] args)
    {
        new Thread2();
    }

    public Thread2()
    {
        while(run)
        {
            try
            {
                switch(state)
                {
                    case 0:
                        Thread.sleep(500);
                        state = 1;
                        break;
                    case 1:
                        doSomeStuff();
                        state = 0;
                    break;
                }
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    private void doSomeStuff() throws InterruptedException
    {
        System.out.println("Hello from thread 2");
    }
}
Avatar billede arne_v Ekspert
19. april 2004 - 14:19 #1
I am a bit confused.

Basicly there are two ways to do threads:
  extends Thread
  implements Runnable

Your first example uses the last one.

Your last example does not use threads at all.
Avatar billede arne_v Ekspert
19. april 2004 - 14:21 #2
I wrote an article describing both ways:
  http://www.eksperten.dk/artikler/27

(in danish, but the code is still Java !)
Avatar billede arne_v Ekspert
19. april 2004 - 14:21 #3
answer
Avatar billede arne_v Ekspert
19. april 2004 - 14:22 #4
The usual argument for implements Runnable is that it can be used
even though the class already extends a class.
Avatar billede dsj Nybegynder
19. april 2004 - 14:29 #5
If we look at the two possibilities that arne_v is mentioning: extends Thread og implements Runnable, the last one i would say is always the best.

There is no difference in the way the Thread works, but if you extends Thread, you WILL have to start the thread in the constructor. If you do not do that, you might not be sure that the thread is started ever started.

If you instantiates a class extending Thread without starting the thread, you will have an unstarted thread/process-instance allocated in the OS's kernel. Even if you drop all references to the class extending Thread, this class-instance will never be garbage collected, because the unstarted thread is holding a reference. This will both result in an ugly memory-leak AND the kernel having one more thread/proces that never gets started nor removed.
Avatar billede dsj Nybegynder
19. april 2004 - 14:34 #6
If you are always 100 percent sure, that the thread is started when extending Thread, there is really no difference besides what arne_v mentions, that implementing Runnable is a more flexible solution, becuse you have te possibility to extend other classes instead.
Avatar billede fredand Forsker
19. april 2004 - 16:18 #7
Hello Mates!

But what thread are then sleeping in Thread2 at the line:
Thread.sleep(500);
Does this sleeps the JVM-process or which thread does it affect?

Best regards
Fredrik
Avatar billede dsj Nybegynder
19. april 2004 - 16:40 #8
It affects the currently running thread: Thread.currentThread();
Avatar billede arne_v Ekspert
19. april 2004 - 16:43 #9
Thread.sleep(500);

simply means: wait 0.5 second
Avatar billede conrad Nybegynder
19. april 2004 - 17:28 #10
Just to add to the discussion: In my opinion you should never let the thread class itself call start, and definitively not in its constructor since this can cause race conditions.

You don't always know who will use and derive from your classes in the future which can cause problems as the small fictive example below illustrates:

import java.awt.*;
import java.applet.*;

public class Thread1 extends Thread
{
   
   
    public Thread1()
    {
        start();
    }

    public void run()
    {}
}

import java.awt.*;
import java.applet.*;

public class Thread2 extends Thread1
{
    boolean run= true;
    int state = 0;
    int[] someResource;

    public static void main(String[] args)
    {
        new Thread2();
    }
   
    public Thread2()
    {
        super();
        //simulate some lenghty initialization
        try
        {
            sleep(500);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        //something is initialized after start() is actually called
        someResource = new int[1000];
        for(int i = 0;i < 1000;i++)
        {
            someResource[i] = i;
        }
    }

    public void run()
    {
        while(run)
        {
            try
            {
              doSomeStuff();
               
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }   

    private synchronized void doSomeStuff() throws InterruptedException
    {
        System.out.println("Hello from thread 2");
        //is someResource ready ???
        for(int i = 0; i < 1000;i++)
        {
            System.out.println("someResource[i] = "+ someResource[i]);
        }
    }
}
Avatar billede dsj Nybegynder
19. april 2004 - 17:50 #11
Conrad >> I suppose you would rather prefer a memory-leak and total machine crash, than starting the Thread in the derived class? My opinion is still that the best way is to implement Runnable - but having unstarted threads in kernel woithout the possibility to remove them without restarting the JVM is very serious. I have seen an example were a server chrashed daily because of this bug. In rare cases the threads did not get started, and when the server-load increased, the server simply chrashed because of full memory, used by the kernel.
Avatar billede dsj Nybegynder
19. april 2004 - 17:53 #12
That "You don't always know who will use and derive from your classes in the future" is actually I think, the primary reason to start the thread in the constructor of the derived class. You cannot be sure, that the thread is always started, which results in a heavy memory-leak - this is never acceptable.
Avatar billede conrad Nybegynder
19. april 2004 - 18:42 #13
I don't have any experience with server programming and problems like the one you encountered, so I am really not an expert on that area, and I was thinking more in application development.

I do however find it hard to see why it should be a problem  to instantiate the thread and the call start() like below ? (of cause you can't prevent that people forget)

Thread1 t = new Thread1();
t.start();

but maybe you can tell me when this can be a problem ?

To support my case I will mention that javas own implementation of threads
does not start the thread in the constructor :)
Avatar billede arne_v Ekspert
19. april 2004 - 19:19 #14
1)

Whether to use extends Thread or implements Runnable and whether to start
the thread in the constructor or not must be two independent questions - all
four combinations are valid

2)

I usually use extends Thread and call start after having created the object
Avatar billede arne_v Ekspert
19. april 2004 - 19:19 #15
re 2)

Because I think the code is easiest to read then
Avatar billede fredand Forsker
20. april 2004 - 09:34 #16
Hello mates!

It is always interesting to get experts opinions, and for me everything seems more clearer.

Since Conrad took part of the disscusion I think he salso should take part of the points. So if you see this conrad, just throw in a Svar so I could give you your part of the points.

Best regards
Fredrik
Avatar billede conrad Nybegynder
20. april 2004 - 10:48 #17
svar
Avatar billede fredand Forsker
20. april 2004 - 10:49 #18
Thanks mates!

/Fredrik
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester