• Main Page
  • Related Pages
  • Classes
  • Files
  • File List

JPWorld.java

Go to the documentation of this file.
00001 
00002 import java.awt.BorderLayout;
00003 import java.awt.Color;
00004 import java.awt.Dimension;
00005 import java.awt.Font;
00006 import java.awt.Graphics;
00007 import java.awt.GraphicsConfiguration;
00008 import java.awt.Toolkit;
00009 import java.awt.event.ActionEvent;
00010 import java.awt.event.ActionListener;
00011 import java.awt.event.KeyEvent;
00012 import java.awt.event.KeyListener;
00013 
00014 import javax.swing.JComponent;
00015 import javax.swing.JFrame;
00016 import javax.swing.JScrollPane;
00017 import javax.swing.JTextArea;
00018 import javax.swing.ScrollPaneConstants;
00019 import javax.swing.SwingUtilities;
00020 import javax.swing.Timer;
00021 
00022 /**
00023  *  The <code>JPWorld</code> class encapsulates artificial world of charged and neutral
00024  *  particles governed by physical laws, i.e. electrical and gravitational forces as well
00025  *  Newton's law of motions. The motion of each particle is calculated in a separate
00026  *  thread belonging to instance of <code>Particle</code> class. The interacting forces
00027  *  between particles are calculated in single thread for several <code>Particle</code>s
00028  *  belonging to the same <code>WorldOfParticles</code>. Instance of the 
00029  *  <code>WorldOfParticles</code> is rendered (and animated) inside (as a part of) 
00030  *  the <code>JPWorld</code>.
00031  *  
00032  *  Application's short-cut key are summarized in <code>printUsage()</code>.
00033  *   
00034  *  @author  Mikica B Kocic
00035  *
00036  */
00037 public class JPWorld extends JComponent 
00038      implements ActionListener, KeyListener, WorldOfParticles.RenderingContext 
00039 {
00040     /**
00041      *  Implements java.io.Serializable interface
00042      */
00043     private static final long serialVersionUID = 1274716824806299281L;
00044 
00045     /**
00046      *  The instance of the world of particles that we are rendering. 
00047      */
00048     private WorldOfParticles world = null;
00049 
00050     /**
00051      *  Special particle with very huge mass, also called The Big Blue.
00052      *  It can be moved by the user. 
00053      */
00054     private Particle hugeMass = null;
00055 
00056     /**
00057      *  Creation of new particles <i>should</i> try to keep total amount of particles in 
00058      *  the world bellow this limit. 
00059      */
00060     private final int maxParticlesAllowed = 100;
00061     
00062     /**
00063      *  Animation timer used to trigger rendering 
00064      */
00065     private Timer timer = null;
00066 
00067     /**
00068      *  Base animation timer resolution 
00069      */
00070     private int animationTimerResolution = 5;
00071 
00072     /**
00073      *  The background color shade of gray
00074      */
00075     private int backgroundColor = 255;
00076 
00077     /**
00078      *  Indicates whether to annotate forces acting on particles or not. 
00079      */
00080     private volatile boolean annotateForces = true;
00081 
00082     /**
00083      *  Log pane containing log area
00084      */
00085     private JScrollPane logPane = null;
00086     
00087     /**
00088      *  Log (debug, info, error...) messages (instead of System.out).
00089      */
00090     private JTextArea logf = null;
00091 
00092     /**
00093      *  Instance of the T3 class (used to test T1 & T2 classes) 
00094      */
00095     private T3 testerThread = null;
00096 
00097     /**
00098      *  Creates a new instance of Particle thread tester 
00099      */
00100     public JPWorld ()
00101     {
00102         this.setLayout( new BorderLayout () );
00103 
00104         /* Create log area used to display textual information to user
00105          */
00106         createLogArea ();
00107 
00108         /* Create world of particles...
00109          */
00110         world = new WorldOfParticles( this );
00111 
00112         /* Start animation timer...
00113          */
00114         startAnimation( animationTimerResolution );
00115     }
00116 
00117     /**
00118      *  Shows short-cut keys and application usage in log area.
00119      */
00120     public void printUsage ()
00121     {
00122         synchronized( this )
00123         {
00124             /* Do not print usage while testerThread is running
00125              */
00126             if ( testerThread != null ) {
00127                 return;
00128             }
00129 
00130             clearLogArea ();
00131             
00132             boolean hasFrame = ( SwingUtilities.getRoot(this) instanceof RunStandalone );
00133             
00134             /* Now, show short-cut keys...
00135              */
00136             println( "" );
00137             println( "        Usage:" );
00138             println( "------- ----------------------" );
00139             println( "   A    create one +/- pair" );
00140             println( "   B    create 5 pairs of +/-" );
00141             println( "   C    create 50 pairs of +/-" );
00142             println( "   E    centripetalize vel." );
00143             
00144             if ( hasFrame ) {
00145                 println( "   F    toggle fullscreen" );
00146             }
00147 
00148             println( "   H    help (usage)" );
00149             println( "   N    annotate forces" );
00150             println( "   O    slow-down time" );
00151             println( "   P    speed-up time" );
00152             println( "   R    reset all velocities" );
00153             println( "   T    start tests" );
00154             println( "   +    inc. frame interval" );
00155             println( "   -    dec. frame interval" );
00156             println( " space  freeze/unfreeze" );
00157             println( " arrows move The Big Blue" );
00158             
00159             if ( hasFrame ) {
00160                 println( "  esc   exit fullscreen" );
00161             }
00162             
00163             println( "" );
00164         }
00165     }
00166 
00167     /**
00168      *  Indicates if in fullscreen mode
00169      */
00170     private boolean isFullScreen ()
00171     {
00172         if ( ! ( SwingUtilities.getRoot( this ) instanceof RunStandalone ) ) {
00173             return false;
00174         }
00175         
00176         RunStandalone jf = (RunStandalone)( SwingUtilities.getRoot( this ) );
00177         
00178         return jf.isUndecorated ();
00179     }
00180     
00181     /**
00182      *  Exits full-screen mode
00183      */
00184     private void exitFullScreen ()
00185     {
00186         if ( isFullScreen () ) {
00187             toggleFullScreen ();
00188         }
00189     }
00190     
00191     /**
00192      *  Toggles full-screen mode
00193      */
00194     private void toggleFullScreen ()
00195     {
00196         if ( ! ( SwingUtilities.getRoot( this ) instanceof RunStandalone ) ) {
00197             return; // not applicable to Applet mode
00198         }
00199         
00200         RunStandalone jf = (RunStandalone)( SwingUtilities.getRoot( this ) );
00201         
00202         /* suppress repaints and notifications
00203          */
00204         jf.setVisible( false );
00205         jf.setIgnoreRepaint( true );
00206         jf.removeNotify ();
00207         
00208         /* toggle window title and border
00209          */
00210         jf.setUndecorated( ! jf.isUndecorated () );
00211 
00212         /* enable repaints and notifications, then show visible
00213          */
00214         jf.addNotify ();
00215         jf.setIgnoreRepaint( false );
00216         
00217         /* rearange components and windows position
00218          */
00219         if ( jf.isUndecorated () )
00220         {
00221             logPane.setVisible( false );
00222             
00223             /* maximize window
00224              */
00225             jf.setExtendedState( jf.getExtendedState() | JFrame.MAXIMIZED_BOTH );
00226         }
00227         else
00228         {
00229             /* Adjust window dimensions not to exceed screen dimensions ...
00230              */
00231             Dimension win = new Dimension( 1024, 600 );
00232             Dimension scsz = Toolkit.getDefaultToolkit().getScreenSize();
00233             win.width  = Math.min( win.width, scsz.width );
00234             win.height = Math.min( win.height, scsz.height - 40 );
00235             jf.setSize( win );
00236             
00237             /* ... then center window on the screen.
00238              */
00239             jf.setLocation( ( scsz.width - win.width )/2, 
00240                             ( scsz.height - 40 - win.height )/2 );
00241 
00242             logPane.setVisible( true );
00243         }
00244 
00245         jf.setVisible( true );
00246         jf.toFront(); 
00247     }
00248 
00249     /**
00250      *  Creates log area for local print-outs.
00251      */
00252     private void createLogArea ()
00253     {
00254         synchronized( this )
00255         {
00256             if ( logf != null ) {
00257                 return;
00258             }
00259                 
00260             /* Log area GUI component
00261              */
00262             logf = new JTextArea ();
00263             
00264             logf.setLineWrap( true );
00265             logf.setWrapStyleWord( true );
00266             logf.setEditable( false );
00267             logf.setPreferredSize( new Dimension( 250, 0 ) );
00268             logf.setFont( new Font( Font.MONOSPACED, Font.PLAIN, 14 ) );
00269             logf.setBackground( new Color( 255, 255, 192 ) );
00270             logf.setForeground( new Color(   0,   0, 192 ) );
00271             logf.addKeyListener( this );
00272             
00273             /* Log area is scrollable...
00274              */
00275             logPane = new JScrollPane( logf );
00276             logPane.setHorizontalScrollBarPolicy(
00277                     ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
00278             add( logPane, BorderLayout.EAST );
00279         }
00280     }
00281 
00282     /**
00283      *  Clears log area
00284      * 
00285      */
00286     public void clearLogArea ()
00287     {
00288         synchronized( this ) 
00289         {
00290             if ( logf != null ) {
00291                 logf.selectAll ();
00292                 logf.replaceSelection( "" );
00293                 logf.setRows( 0 );
00294             }
00295         }
00296     }
00297     
00298     /**
00299      *  Logs a single line of message.
00300      *  
00301      *  @param str  contains message to be shown
00302      */
00303     public void println( String str )
00304     {
00305         synchronized( this )
00306         {
00307             System.out.println( str );
00308 
00309             if ( logf == null ) {
00310                 return;
00311             }
00312 
00313             logf.append( str + "\n" );
00314             logf.setRows( logf.getRows () + 1 );
00315             logf.setCaretPosition( logf.getText().length () );
00316         }
00317     }
00318     
00319     /**
00320      *  Starts T1 & T2 tests (delayed for spec. time) in separate thread.
00321      *  
00322      *  @param delaySec  delay in seconds
00323      */
00324     public void startTests( float delaySec )
00325     {
00326         synchronized( this )
00327         {
00328             if ( testerThread == null )
00329             {
00330                 testerThread = new T3( this, 5.0f, delaySec );
00331                 testerThread.start ();
00332             }
00333         }
00334     }
00335 
00336     /**
00337      *  Adjusts view to current number of particles in the underlying world. 
00338      *  Triggered by <code>WorldOfParticles</code> after some particles are
00339      *  added or removed from the world.
00340      *
00341      *  <strong>Warning:</strong> Method is synchronized (before called) in 
00342      *  <code>WorldOfParticles</code> context. To avoid dead-locks, do not use 
00343      *  <code>synchronized</code> inside the method.
00344      *  
00345      *  @param newParticleCount  current particle count in the instance of
00346      *                           the <code>WorldOfParticles</code>
00347      */
00348     @Override
00349     public void onParticleCountChanged( int newParticleCount )
00350     {
00351         /* Suppress 'force annotations' when particle count exceeds some limit
00352          * then enable them back when it drops down bellow some (other) limit
00353          */
00354         if ( annotateForces && newParticleCount > 20 ) {
00355             annotateForces = false;
00356         } else if ( ! annotateForces && newParticleCount < 15 ) {
00357             annotateForces = true;
00358         }
00359 
00360         /* Keep CPU happy reducing the frame-rate if there are too many particles
00361          * to render.
00362          */
00363         if ( animationTimerResolution < 20 && newParticleCount > 40 ) {
00364             startAnimation( 20 );
00365         } else if ( animationTimerResolution >= 20 && newParticleCount < 40 ) {
00366             startAnimation( 5 );
00367         }
00368     }
00369 
00370     /**
00371      *  Gets boundaries of infinite potential barrier keeping particles together.
00372      */
00373     @Override
00374     public WorldOfParticles.Barrier getBarrier ()
00375     {
00376         int logWidth = logPane != null && logPane.isVisible () ? logPane.getWidth () : 0;
00377         
00378         return world.new Barrier( 
00379                 15, 15, getWidth () - logWidth - 15, getHeight () - 15 
00380                 ); // component width reduced for the log area and 15 pixels around
00381     }
00382 
00383     /**
00384      *  Gets the GraphicsConfiguration associated with parent Component.
00385      * 
00386      * @return the GraphicsConfiguration used by parent's Component or null
00387      */
00388     @Override
00389     public GraphicsConfiguration getGraphicsConfiguration ()
00390     {
00391         return super.getGraphicsConfiguration ();
00392     }
00393 
00394     /**
00395      *  Creates pairs of charged particles. Particles are not created
00396      *  after exceeding some limit.
00397      *  
00398      *  @param count     number of particle pairs to create
00399      *  @param lifeTime  particle life-time in seconds
00400      */
00401     public void createPairOfChargedParticles( int count, double lifeTime )
00402     {
00403         if ( world.getParticleCount () >= maxParticlesAllowed ) {
00404             return;
00405         }
00406 
00407         for ( int i = 0; i < count; ++i )
00408         {
00409             double x = ( getWidth  () - 100 ) * Math.random ();
00410             double y = ( getHeight () - 100 ) * Math.random ();
00411             
00412             world.addNewParticle( 1.0, +1.0, // mass and charge
00413                     x + 100 * Math.random (), // x-pos
00414                     y + 100 * Math.random (), // y-pos
00415                     0.0, // radius 0 == random
00416                     lifeTime + Math.random () * 2 // life time
00417                     );
00418             
00419             world.addNewParticle( 1.0, -1.0, // mass and charge
00420                     x - 100 * Math.random (),
00421                     y - 100 * Math.random (),
00422                     0.0, // radius 0 == random
00423                     lifeTime + Math.random () * 2 // life time
00424                     );
00425         }
00426     }
00427 
00428     /**
00429      *  Call-back from T3 after all tests have been completed.
00430      */
00431     public void afterTestsCompleted ()
00432     {
00433         synchronized( this )
00434         {
00435             testerThread = null; // new tests won't start if testerThread != null
00436 
00437             println( "" );
00438             println( "Press H for usage..." ); // remind user...
00439             println( "" );
00440         }
00441     }
00442 
00443     /** 
00444      *  Paints the component i.e. renders the world of particles
00445      */
00446     @Override
00447     public void paintComponent( Graphics g )
00448     {
00449         /* Erase the background
00450          */
00451         g.setColor( new Color( backgroundColor, backgroundColor, backgroundColor ) );
00452         g.fillRect( 0, 0, getWidth(), getHeight() );
00453 
00454         /* Engrave background with the information such as particle count,
00455          * frame-rate and time scale
00456          */
00457         {
00458             int x = 10, y = 0, dy = 20; // position and delta
00459 
00460             g.setColor( Color.BLUE );
00461             
00462             g.drawString(
00463                     String.format( "N = %d particles", world.getParticleCount () ),
00464                     x, ( y += dy )
00465                     );
00466             
00467             g.drawString(
00468                     String.format( "Frame-rate: %2$.0f Hz (%1$d ms)", 
00469                         animationTimerResolution, 1000f / (float)animationTimerResolution
00470                         ),
00471                     x, ( y += dy )
00472                     );
00473             
00474             g.drawString(
00475                     String.format( "Time scale: %.2f", 
00476                         world.getTimeScale ()
00477                         ),
00478                     x, ( y += dy )
00479                     );
00480 
00481             if ( isFullScreen () ) {
00482                 g.setColor( Color.GRAY );
00483                 
00484                 g.drawString( "Press ESC to exit fullscreen mode...",
00485                         x, ( y += dy )
00486                         );
00487             }
00488         }
00489 
00490         /* Finally, render instance of the world of particles.
00491          */
00492         world.paint( g, annotateForces );
00493     }
00494 
00495     /**
00496      *  Handles events from the Swing timer. Timer is used to render animation frames
00497      *  at specific animation frame rate.
00498      */
00499     @Override
00500     public void actionPerformed( ActionEvent ae )
00501     {
00502         /* Do not allow an empty worlds
00503          */
00504         if ( world.getParticleCount () == 0 )
00505         {
00506             /* Create one huge mass
00507              */
00508             hugeMass = world.addNewParticle( 
00509                     1e12, 0.0, // mass and charge
00510                     getWidth ()/2 - 200, getHeight () / 2, 25.0, // position and radius
00511                     Double.POSITIVE_INFINITY // life time
00512                     ); 
00513 
00514             /* Create one slightly large mass as a satellite
00515              */
00516             world.addNewParticle( 
00517                     1e11, 0.0, // mass and charge
00518                     getWidth ()/2, getHeight () / 2, 20.0, // position and radius
00519                     Double.POSITIVE_INFINITY // life time
00520                     ); 
00521 
00522             /* Create an initial pair of charged particles
00523              */
00524             createPairOfChargedParticles( 1, Double.POSITIVE_INFINITY );
00525         }
00526 
00527         /* Fade-in/out background depending on number of particles
00528          * (keeping backgroundColor *always* in valid range while changing).
00529          */
00530         int alpha = backgroundColor;
00531         
00532         if ( world.getParticleCount () > 35 && alpha > 102 ) {
00533             --alpha;
00534         }
00535         else if ( world.getParticleCount () > 55 && alpha > 0 ) {
00536             --alpha;
00537         }
00538         else if ( world.getParticleCount () < 55 && alpha < 102 ) {
00539             ++alpha;
00540         }
00541         else if ( world.getParticleCount () < 20 && alpha < 255 ) {
00542             ++alpha;
00543         }
00544 
00545         backgroundColor = alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
00546         
00547         repaint ();
00548     }
00549     
00550     /**
00551      *  Moves the frame-rate up/down by changing the timer resolution
00552      *  
00553      *  @param delta  delta timer resolution in millis
00554      */
00555     private void changeAnimationResolution( int delta ) {
00556 
00557         int newResolution = animationTimerResolution;
00558         
00559         newResolution += delta;
00560 
00561         newResolution = Math.max( newResolution, 0 );
00562         newResolution = Math.min( newResolution, 500 );
00563         
00564         startAnimation( newResolution );
00565     }
00566     
00567     /**
00568      *  Starts the animation if not already started, and changes frame-rate
00569      *  
00570      *  @param resolution   frame rate timer resolution in millis
00571      */
00572     private void startAnimation( int resolution ) 
00573     {
00574         if ( timer != null ) {
00575             timer.stop ();
00576             timer.setDelay( resolution );
00577         } else {
00578             timer = new Timer( resolution, this );
00579         }
00580         
00581         animationTimerResolution = resolution;
00582         
00583         timer.start ();
00584     }
00585 
00586     /**
00587      *  Implements <code>KeyListener</code>'s key pressed event.
00588      *  Toggles various rendering flags.
00589      */
00590     @Override
00591     public void keyPressed( KeyEvent ke ) {
00592         
00593         int keyCode = ke.getKeyCode ();
00594         
00595         switch( keyCode )
00596         {
00597         case KeyEvent.VK_A:
00598             /* create a pair of charged particles with life-time 20 ± 10 sec */
00599             createPairOfChargedParticles( 1, 15.0 + Math.random () * 10.0 );
00600             break;
00601             
00602         case KeyEvent.VK_B:
00603             /* create five pairs of charged particles with life-time 10 ± 2.5 sec */
00604             createPairOfChargedParticles( 5, 7.5 + Math.random () * 5.0 );
00605             break;
00606             
00607         case KeyEvent.VK_C:
00608             createPairOfChargedParticles( 50, 60 + Math.random () * 20.0 );
00609             break;
00610             
00611         case KeyEvent.VK_D:
00612             world.dump (); // dump to System.out all particle physical props.
00613             break;
00614 
00615         case KeyEvent.VK_F:
00616             toggleFullScreen ();
00617             break;
00618 
00619         case KeyEvent.VK_ESCAPE:
00620             exitFullScreen ();
00621             break;
00622             
00623         case KeyEvent.VK_H:
00624             printUsage ();
00625             break;
00626             
00627         case KeyEvent.VK_E:
00628             world.makeCentripetalVelocities ();
00629             break;
00630             
00631         case KeyEvent.VK_R:
00632             world.resetVelocities (); // set all velocities to 0
00633             break;
00634             
00635         case KeyEvent.VK_O:
00636             world.incTimeScale( -0.1 ); // slow-down world's time
00637             break;
00638             
00639         case KeyEvent.VK_P:
00640             world.incTimeScale( +0.1 ); // speed-up world's time
00641             break;
00642             
00643         case KeyEvent.VK_UP:
00644             if ( hugeMass != null ) {
00645                 hugeMass.moveParticle( 0, -10 );
00646             }
00647             break;
00648             
00649         case KeyEvent.VK_DOWN:
00650             if ( hugeMass != null ) {
00651                 hugeMass.moveParticle( 0, +10 );
00652             }
00653             break;
00654             
00655         case KeyEvent.VK_LEFT:
00656             if ( hugeMass != null ) {
00657                 hugeMass.moveParticle( -10, 0 );
00658             }
00659             break;
00660             
00661         case KeyEvent.VK_RIGHT:
00662             if ( hugeMass != null ) {
00663                 hugeMass.moveParticle( +10, 0 );
00664             }
00665             break;
00666             
00667         case KeyEvent.VK_T:
00668             startTests( 0f );
00669             break;
00670 
00671         case KeyEvent.VK_N:
00672             annotateForces = ! annotateForces;
00673             break;
00674 
00675         case KeyEvent.VK_SPACE:
00676             world.togglePaused (); // stop/continue physical calculations
00677             break;
00678 
00679         case KeyEvent.VK_PLUS:
00680         case KeyEvent.VK_ADD:
00681             changeAnimationResolution( +5 ); // Slow-down frame rate
00682             break;
00683 
00684         case KeyEvent.VK_MINUS:
00685         case KeyEvent.VK_SUBTRACT:
00686             changeAnimationResolution( -5 ); // Speed-up frame rate
00687             break;
00688         }
00689     }
00690 
00691     /**
00692      *  Implements <code>KeyListener</code>'s key released event.
00693      */
00694     @Override
00695     public void keyReleased( KeyEvent ke )
00696     {
00697         /* unused */
00698     }
00699     
00700     /**
00701      *  Implements <code>KeyListener</code>'s key typed event.
00702      */
00703     @Override
00704     public void keyTyped( KeyEvent ke )
00705     {
00706         /* unused */
00707     }
00708 
00709 }
00710 
00711 /*! 
00712  *  \mainpage Multi-threaded World of Particles (WOP)
00713  *
00714  *  \section s_intro Introduction
00715  *  
00716  *  The package implements solution to \ref p_task as a part of 
00717  *  the <a href="http://dsv.su.se/utbildning/distans/ip1" target="_blank"><b>SU/IP1 
00718  *  course</b></a>.
00719  *  
00720  *  \image html wopApp.png
00721  *  
00722  *  \section s_desc Description
00723  *  
00724  *  The application displays an artificial world of charged and electrically neutral
00725  *  particles that are governed by physical laws (i.e. electrical and gravitational 
00726  *  forces as well Newton's law of motions). This world is referred in the rest of 
00727  *  the documentation as the <b>World of Particles</b> or simply the <b>WOP</b>.
00728  *  
00729  *  The motion for each particle in WOP is calculated in its own separate thread 
00730  *  Particle.run() belonging to the instance of Particle class. 
00731  *  The interacting forces between particles are calculated in
00732  *  WorldOfParticles.run() thread common for all particles belonging to
00733  *  the same WorldOfParticles. 
00734  *  Instance of the WorldOfParticles is rendered (and animated) 
00735  *  inside (as a part of) the JPWorld, which extends 
00736  *  <a href="http://download.oracle.com/javase/6/docs/api/javax/swing/JComponent.html">
00737  *  <b>JComponent</b></a>. Particles renders themselves with Particle.paint() in
00738  *  the JPWorld's graphical context.
00739  *  
00740  *  Further, there are three separate classes T1, T2 and T3 
00741  *  that control creation of particles in the WOP (see T1.run, T2.run and T3.run)
00742  *  and as such they demonstrate a solution to \ref p_task.
00743  *
00744  *  \section s_jar Executable
00745  *  
00746  *  The jar file of the package can be found <a href="../wop.jar"><b>here</b></a>.
00747  *  
00748  *  <div style="color:darkred;font-weight:bold;">
00749  *  Application can be run both as stand-alone and as an applet.</div> 
00750  *  
00751  *  Use RunAsApplet class to start application in applet mode.
00752  *  
00753  *  \section s_src Source Files
00754  *  
00755  *   - \ref T1.java
00756  *   - \ref T2.java
00757  *   - \ref T3.java
00758  *   - \ref JPWorld.java
00759  *   - \ref WorldOfParticles.java
00760  *   - \ref Particle.java
00761  *   - \ref RunStandalone.java
00762  *   - \ref RunAsApplet.java
00763  */
00764 /*! 
00765  *  \page p_task IP1-1.1 Uppgift
00766  *  
00767  *  Gör ett program som består av tre klasser:
00768  *   - En huvudklass med en main-metod
00769  *   - En trådad klass T1 som ärver av klassen Thread
00770  *   - En trådad klass T2 som implmenterar interfacet Runnable
00771  *
00772  *  Trådarna ska en gång per sekund skriva ut följande på STDOUT (kommandofönstret):
00773  *   - Tråd T1: Tråd 1
00774  *   - Tråd T2: Tråd 2
00775  *
00776  *  Frivillig utökning är att även titta på hur man pausar trådar och då utöka programmet
00777  *  ovan så huvudklassen gör följande:
00778  *  
00779  *   -#  Skapa och starta en tråd från klass T1 
00780  *   -#  Vänta i 5 sekunder
00781  *   -#  Skapa och starta en tråd från klass T2
00782  *   -#  Vänta i 5 sekunder
00783  *   -#  Pausa tråden från klass T2
00784  *   -#  Vänta i 5 sekunder
00785  *   -#  Aktivera tråden från klass T2
00786  *   -#  Vänta i 5 sekunder
00787  *   -#  Stoppa tråden från klass T1
00788  *   -#  Vänta i 5 sekunder
00789  *   -#  Stoppa tråden från klass T2
00790  *   
00791  *  En annan frivillig utökning är att göra ett program som använder trådar och grafik. 
00792  */
00793 

Generated on Thu Dec 16 2010 12:28:54 for Multi-threaded World of Particles by  doxygen 1.7.2