Solved

Can an applet have multiple threads running?

Posted on 1998-06-17
6
220 Views
Last Modified: 2010-04-16
Here's my basic program:

The user goes to a web page and enters his username and password into the boxes provided.

He then gets shown a calendar window, with the days of a particular month being represented as panels with a number on them.

If he clicks a panel, the program attempts to book him in, sending the booking information to the server.

The server then replies, and he is booked.

The problem that I have, though, is this:

My applet asks for U and P, loads up the calendar window, and initialises it fine.  However, if I then try and get the applet to listen to its socket for incoming information about other bookings, then the calendar window freezes up after initialisation, but before painting.

My initial thought was that (contrary to my expectations) the calendar window was being initiated by the same thread that listened for input, and as painting was lower priority than direct instructions, the program was stopping at this point.

However, when I tried to put the calendar window initiation on a new thread (so that both could run in parallel, time-sharing), the window still freezes up!

Any suggestions?
0
Comment
Question by:sstephens
6 Comments
 
LVL 5

Expert Comment

by:fontaine
Comment Utility
That's a first guess. Are you doing the communication part of your program in a event
handler  (ex: action(Even e, Object o), actionPerformed(ActionEvent e), etc.)? When you
are in an event handler, no other event can indeed be processed. The solution is to handle
what is currently handled by this method in a separate thread.

If this comment doesn't help you, the best is either to post the full code, or better, to reproduce
the problem in a short functioning example (i.e. something that we can recompile and test).
0
 

Author Comment

by:sstephens
Comment Utility
I'm not doing the comms part in an event handler.  In fact, the entire calendar window is (supposedly) being handled by a different thread!

I don't think that I can reproduce the problem in a short functioning example, but I'll try.  As soon as I've done so, will post to here.

Shane
0
 

Author Comment

by:sstephens
Comment Utility
OK - reproduced the problem in a short(er) functioning(ish) example.  Jus' follow these instructions (although it's probably the blind leading the perfectly aware, here):

1) copy the following 2 sections into 2 files called LTTheApplet.java and LTmyApplet.html respectively

2) compile LTTheApplet.java

3) (if you're using Unix, otherwise I don't know how) type java LTSocketManager& to run the socketmanager in the background

4) type appletviewer LTmyApplet.html

5) for username, put "Hi".  For password, put ANYTHING (but DO NOT leave it blank - it's a bug that I haven't fixed yet...)

6) Notice that although the new window has strict instructions to repaint itself with a number, it doesn't.  Also notice that when you click on the applet, the intended response (to print a message to System.out) doesn't happen.  Finally, notice that when you remove the command to ListenForInput (or whatever it is), then the rest works fine (I hope - haven't checked...)


---FILE1---

import java.io.*;
import java.net.*;
import java.util.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;

class LTSocketManager {

      LTProgramSocket myPS;
      Socket mySocket;
      InputStream in;
      OutputStream out;
      DataInputStream datain;
      DataOutputStream dataout;
      static LTSocketManager me;


      public static void main (String args[]) {
            me = new LTSocketManager();
      }


      LTSocketManager() {
      
            try {
                  ServerSocket myServerSocket = new ServerSocket(5000, 100);

                  myPS = new LTProgramSocket(5000, myServerSocket, this);
                  myPS.start();
            }
            catch(IOException e) {
                  e.printStackTrace();
            }
      }
}

class LTProgramSocket extends Thread  {
 
      private int myPort;
      ServerSocket myServerSocket;

      InputStream in;
      OutputStream out;
      DataInputStream datin;
      DataOutputStream datout;
      Socket mySocket;
      StringTokenizer st;
      LTSocketManager myMan;


      LTProgramSocket(int port, ServerSocket extSock, LTSocketManager extMan) {
            
            super();
            myPort = port;
            myServerSocket = extSock;
            myMan = extMan;

      }

      public void run() {

            try {
                  doServerStuff();
            }
            catch (IOException e) {
                  e.printStackTrace();
                  System.exit(0);
            }

            }

      public void doServerStuff() throws IOException {
      
            
            mySocket = myServerSocket.accept();
            System.out.println("Socket Created");

            in = mySocket.getInputStream();
            out = mySocket.getOutputStream();

            datout = new DataOutputStream(out);
            datin = new DataInputStream(in);

            datout.writeUTF("R");
            datout.flush();

            
            boolean vfied = false;
            while (!vfied) {
                  vfied = recieveVerification();
            }
            
            waitForInput();            

            System.exit(1);      
            
      }

      public boolean recieveVerification() throws IOException {
            

            String command;
            char comchars[] = {0,0};


            command =  datin.readUTF();

            String uAndp = datin.readUTF();
            System.out.println(uAndp);
            st = new StringTokenizer(uAndp, ";");
            String gName = st.nextToken();
            String pWord = st.nextToken();
            
            if (gName.equals("Hi")) {
                  datout.writeUTF("V");
                  return false;
            }
            datout.writeUTF("F");
            return true;
      }
      
      

                  
            
      public void waitForInput() throws IOException {
            
            String command;
            
            while(true) {
                  command = datin.readUTF();
                  if (command.equals("B")) {
                        System.out.println("Got command!");
                  }
            }
      }
}

public class LTTheApplet extends Applet implements ActionListener{

      Socket mySocket;
      InputStream in;
      OutputStream out;
      DataOutputStream dataout;
      DataInputStream datain;

      Label plabel, ulabel;
      TextField password, username;
      Button verify;

      LTAppletWindow myCalender;

      public void init() {


            try {

                  String host = getCodeBase().getHost();

                  mySocket = new Socket(host, 5000);
                  
                  in = mySocket.getInputStream();
                  datain = new DataInputStream(in);
                  
                  out = mySocket.getOutputStream();
                  dataout = new DataOutputStream(out);
                  
                  String command = datain.readUTF();

                  ulabel = new Label("Username");
                  add(ulabel);
                  username = new TextField(10);
                  add(username);
                  
                  plabel = new Label("Password");
                  add(plabel);
                  password = new TextField(10);
                  add(password);
                  
                  verify = new Button("OK");
                  verify.addActionListener(this);

                  add(verify);
            }
            catch(IOException e) {
                  e.printStackTrace();
            }
      }

      public void actionPerformed(ActionEvent e) {

            if (e.getSource() == verify) {
                  boolean verified = sendInfo();
                  if (verified == true) {
                        System.out.println("Verified");
                        showPanel();
                  }
            }
      }

      public boolean sendInfo() {

            try {
                  dataout.writeUTF("V");

                  String p1 = username.getText();
                  String p2 = password.getText();
                  String uandp = p1 + ";" + p2;


                  dataout.writeUTF(uandp);
                  dataout.flush();
                  System.out.println("Client:data sent - " + uandp);
                  System.out.println("Client:waiting for response");
                  String command =  datain.readUTF();
                  System.out.println(command);

                  if (command.equals("V")) return true;
                  return false;

            }
            catch (IOException f) {
                  f.printStackTrace();
                  return false;
            }
      }
      public void showPanel() {
      
            LTAppletThread myThread = new LTAppletThread(this);
            myThread.start();
            try {
                  waitForInput();
            }
            catch (IOException g) {}


      }

      public void waitForInput() throws IOException {
            
            String command;
            
            while(true) {
                  command = datain.readUTF();
                  System.out.println("!iO");
                  if (command.equals("B")) {
                        System.out.println("Applet recieved command!");
                  }
            }
      }
}

class LTAppletThread extends Thread {

      LTTheApplet ta;
      LTAppletWindow myCalender;

      LTAppletThread(LTTheApplet a) {

            ta = a;

      }

      public void run() {

            myCalender = new LTAppletWindow(ta);
            myCalender.resize(500,500);
            myCalender.show();

      }
}
class LTAppletWindow extends Frame {

      LTTheApplet mySuper;
      LTDayPanel myPanel;

      LTAppletWindow(LTTheApplet ta1) {

            super();
            mySuper = ta1;
            
            
            myPanel = new LTDayPanel(this);
            add(myPanel);
            myPanel.addMouseListener((MouseListener) myPanel);
            myPanel.setBlack(7);
            myPanel.sBack();
                  
      }
}
class LTDayPanel extends Panel implements MouseListener{

      LTAppletWindow mySuper;
      int myNum;

      LTDayPanel(LTAppletWindow aw) {
            mySuper = aw;
      }

      
      public void setBlack(int i) {
      
            myNum = i;
            repaint();

      }
      
      public void sBack() {
            setBackground(Color.blue);
            repaint();
      }
      
      public void paint(Graphics g) {
      
            setForeground(Color.black);
            g.drawString(myNum + "", 100, 100);
      }


      public void mouseClicked(MouseEvent e) {
      
            System.out.println("Hi!");
            
      }
      public void mouseEntered(MouseEvent e) {}
      public void mouseExited(MouseEvent e) {}
      public void mousePressed(MouseEvent e) {}
      public void mouseReleased(MouseEvent e) {}
}




<HTML>
<BODY>
<APPLET code="LTTheApplet.class" width=200 height=100></APPLET>
</BODY>import java.io.*;
import java.net.*;
import java.util.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;

class LTSocketManager {

      LTProgramSocket myPS;
      Socket mySocket;
      InputStream in;
      OutputStream out;
      DataInputStream datain;
      DataOutputStream dataout;
      static LTSocketManager me;


      public static void main (String args[]) {
            me = new LTSocketManager();
      }


      LTSocketManager() {
      
            try {
                  ServerSocket myServerSocket = new ServerSocket(5000, 100);

                  myPS = new LTProgramSocket(5000, myServerSocket, this);
                  myPS.start();
            }
            catch(IOException e) {
                  e.printStackTrace();
            }
      }
}

class LTProgramSocket extends Thread  {
 
      private int myPort;
      ServerSocket myServerSocket;

      InputStream in;
      OutputStream out;
      DataInputStream datin;
      DataOutputStream datout;
      Socket mySocket;
      StringTokenizer st;
      LTSocketManager myMan;


      LTProgramSocket(int port, ServerSocket extSock, LTSocketManager extMan) {
            
            super();
            myPort = port;
            myServerSocket = extSock;
            myMan = extMan;

      }

      public void run() {

            try {
                  doServerStuff();
            }
            catch (IOException e) {
                  e.printStackTrace();
                  System.exit(0);
            }

            }

      public void doServerStuff() throws IOException {
      
            
            mySocket = myServerSocket.accept();
            System.out.println("Socket Created");

            in = mySocket.getInputStream();
            out = mySocket.getOutputStream();

            datout = new DataOutputStream(out);
            datin = new DataInputStream(in);

            datout.writeUTF("R");
            datout.flush();

            
            boolean vfied = false;
            while (!vfied) {
                  vfied = recieveVerification();
            }
            
            waitForInput();            

            System.exit(1);      
            
      }

      public boolean recieveVerification() throws IOException {
            

            String command;
            char comchars[] = {0,0};


            command =  datin.readUTF();

            String uAndp = datin.readUTF();
            System.out.println(uAndp);
            st = new StringTokenizer(uAndp, ";");
            String gName = st.nextToken();
            String pWord = st.nextToken();
            
            if (gName.equals("Hi")) {
                  datout.writeUTF("V");
                  return false;
            }
            datout.writeUTF("F");
            return true;
      }
      
      

                  
            
      public void waitForInput() throws IOException {
            
            String command;
            
            while(true) {
                  command = datin.readUTF();
                  if (command.equals("B")) {
                        System.out.println("Got command!");
                  }
            }
      }
}

public class LTTheApplet extends Applet implements ActionListener{

      Socket mySocket;
      InputStream in;
      OutputStream out;
      DataOutputStream dataout;
      DataInputStream datain;

      Label plabel, ulabel;
      TextField password, username;
      Button verify;

      LTAppletWindow myCalender;

      public void init() {


            try {

                  String host = getCodeBase().getHost();

                  mySocket = new Socket(host, 5000);
                  
                  in = mySocket.getInputStream();
                  datain = new DataInputStream(in);
                  
                  out = mySocket.getOutputStream();
                  dataout = new DataOutputStream(out);
                  
                  String command = datain.readUTF();

                  ulabel = new Label("Username");
                  add(ulabel);
                  username = new TextField(10);
                  add(username);
                  
                  plabel = new Label("Password");
                  add(plabel);
                  password = new TextField(10);
                  add(password);
                  
                  verify = new Button("OK");
                  verify.addActionListener(this);

                  add(verify);
            }
            catch(IOException e) {
                  e.printStackTrace();
            }
      }

      public void actionPerformed(ActionEvent e) {

            if (e.getSource() == verify) {
                  boolean verified = sendInfo();
                  if (verified == true) {
                        System.out.println("Verified");
                        showPanel();
                  }
            }
      }

      public boolean sendInfo() {

            try {
                  dataout.writeUTF("V");

                  String p1 = username.getText();
                  String p2 = password.getText();
                  String uandp = p1 + ";" + p2;


                  dataout.writeUTF(uandp);
                  dataout.flush();
                  System.out.println("Client:data sent - " + uandp);
                  System.out.println("Client:waiting for response");
                  String command =  datain.readUTF();
                  System.out.println(command);

                  if (command.equals("V")) return true;
                  return false;

            }
            catch (IOException f) {
                  f.printStackTrace();
                  return false;
            }
      }
      public void showPanel() {
      
            LTAppletThread myThread = new LTAppletThread(this);
            myThread.start();
            try {
                  waitForInput();
            }
            catch (IOException g) {}


      }

      public void waitForInput() throws IOException {
            
            String command;
            
            while(true) {
                  command = datain.readUTF();
                  System.out.println("!iO");
                  if (command.equals("B")) {
                        System.out.println("Applet recieved command!");
                  }
            }
      }
}

class LTAppletThread extends Thread {

      LTTheApplet ta;
      LTAppletWindow myCalender;

      LTAppletThread(LTTheApplet a) {

            ta = a;

      }

      public void run() {

            myCalender = new LTAppletWindow(ta);
            myCalender.resize(500,500);
            myCalender.show();

      }
}
class LTAppletWindow extends Frame {

      LTTheApplet mySuper;
      LTDayPanel myPanel;

      LTAppletWindow(LTTheApplet ta1) {

            super();
            mySuper = ta1;
            
            
            myPanel = new LTDayPanel(this);
            add(myPanel);
            myPanel.addMouseListener((MouseListener) myPanel);
            myPanel.setBlack(7);
            myPanel.sBack();
                  
      }
}
class LTDayPanel extends Panel implements MouseListener{

      LTAppletWindow mySuper;
      int myNum;

      LTDayPanel(LTAppletWindow aw) {
            mySuper = aw;
      }

      
      public void setBlack(int i) {
      
            myNum = i;
            repaint();

      }
      
      public void sBack() {
            setBackground(Color.blue);
            repaint();
      }
      
      public void paint(Graphics g) {
      
            setForeground(Color.black);
            g.drawString(myNum + "", 100, 100);
      }


      public void mouseClicked(MouseEvent e) {
      
            System.out.println("Hi!");
            
      }
      public void mouseEntered(MouseEvent e) {}
      public void mouseExited(MouseEvent e) {}
      public void mousePressed(MouseEvent e) {}
      public void mouseReleased(MouseEvent e) {}
}

-END FILE1---


---FILE2---

<HTML>
<BODY>
<APPLET code="LTTheApplet.class" width=200 height=100></APPLET>
</BODY>
</HTML>

---END FILE2---
</HTML>

0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Expert Comment

by:muesli
Comment Utility
Hi,

I'd say that by doing things differently, you could get what you want much more easily:

1.  Don't do this kind of low-level Socket/Thread/Notification programming.  That's what ORBs are for.  For example, RMI, Objectspace Voyager, Visigenic Visibroker, etc.  These will handle multithreading for you.  They are very easy to work with.  Incoming requests are automatically in separate threads.

2.  Don't put this notification code directly into your application code.  Make it a separate application-independent system that can be used by any clients.  Usually this is called a "Publish/Subscribe" system.

Applying both of these ideas will cut your code size by 50%, and make it clearer and more reliable.  I've been where you are - making TCP/IP apps based on my own application-dependent protocol.  I'm a -much- happier camper now that I've gone the ORB route.

If you want, I can post specific examples as an "Answer".
0
 

Author Comment

by:sstephens
Comment Utility
Posting specific examples would be _wonderful_!

However, I must warn you that I am writing this as a booking system for a university machine (ie - the budget is approximately $0...), so that I can really only write using free java classes!  btw, I'm on a Silicon Graphics machine, using java 1.1(?), if that helps.

Another thing - I really would be interested in knowing why my code didn't work!  I know it's messy, and all that, but I thought that the logic in it was still sound.

Thanks,

Shane

0
 
LVL 1

Accepted Solution

by:
VincentT earned 110 total points
Comment Utility
I tried you program and here is what I found:
First, you calendar frame gets painted, but its thread gets starved by the socket listening one.  
In java, you can't assume that your program will run in a VM pre-emptive threading.  For example, in linux, the VM is derived from the solaris one and has only green threads (cooperative threads).  It's really easy to starve a thread on those VM...

If you comment out the code in the waitForInput method, you see the content of the frame.  The while(true) loop is problematic.

Here is the description of Thread.yield() for the jdk1.1.6 javadoc :


  yield()
      Causes the currently executing thread object to temporarily pause and allow other threads to execute.

If this were my code, I would place the SocketListening in a new "well behaved" thread and the gui stuff in the main thread.

A great tool to debug thread problems is the  Hotjava browser.  It sucks at rendering html, but for a developper, it offers a lot.  For exemple, you can show all the running threads of your applet, memory consumption (is this the word?  I speak french..)

Finally, here is an ugly hack that allows to create threads with inner classes...


public void myMethod(){
}

Thread t = new Thread(){
   public void run(){
      myMethod();
   }
};


// This calls "myMethod" is a new unnamed thread
t.start();

// The main thread goes on!
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

For customizing the look of your lightweight component and making it look lucid like it was made of glass. Or: how to make your component more Apple-ish ;) This tip assumes your component to be of rectangular shape and completely opaque. (COD…
This was posted to the Netbeans forum a Feb, 2010 and I also sent it to Verisign. Who didn't help much in my struggles to get my application signed. ------------------------- Start The idea here is to target your cell phones with the correct…
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now