Thread che funzionano solo con le println

di il
6 risposte

Thread che funzionano solo con le println

Ragazzi, sto uscendo pazzo:

Ho un programma applet che funziona correttamente (usando eclipse), questo codice però funziona solo se in un determinato punto inserisco una println...

voglio postarvelo come file zip:

http://www83.zippyshare.com/v/VgfGPTup/file.htm

il codice in esame è:
private class MyThread extends Thread{
		
		private int Mode;
		
		public MyThread(int Mode){
			
			this.Mode=Mode;
		}
		
		public void run(){
			System.out.println(getName()+"running");
			while (true){
				System.out.println("Mode: " + Mode);
				while(runFlag==true){
					
					
					switch(Mode){
					
						case 1:
							
							synchronized(Counter){
									
								Counter++;
							}
							break;
							
						case 2:
							
							synchronized(Counter){
								
								int a=0;
								try {
									
									a = myRMIObj.pow(Counter);
									Pow.setText(""+a);
									T.setText(""+Counter);
								}
								catch (RemoteException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
								
							}
							break;
							
						default:
					}
					try {
						sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
	}
praticamente senza la println ("Mode: "+Mode), i contatori dell'applet non avanzano.... come diamine è possibile?

potete aiutarmi?

6 Risposte

  • Re: Thread che funzionano solo con le println

    Francesco93 ha scritto:


    praticamente senza la println ("Mode: "+Mode), i contatori dell'applet non avanzano.... come diamine è possibile?
    Non ho provato il codice, non avrei tempo in questo momento. La cosa certa che posso dirti è che hai "sorvolato" (e in diversi punti) sulle questioni sui thread, in particolare sulla "visibilità" delle modifiche. Che non hai assolutamente considerato. Il tuo codice quindi non è corretto al 100% e potrebbe anche non funzionare/funzionare male a seconda della JVM, sistema, piattaforma.


    Ne dico giusto una: runFlag è settato nei actionPerformed, quindi è nel contesto del Event Dispatch Thread. E poi runFlag viene letto nel contesto del tuo thread che crei.
    Quando fai lo start() sul Thread, tutto quanto fatto fino a quel momento è "visibile" al nuovo thread. Questa è una garanzia implicita data dallo start.
    Il punto è che i click sui pulsanti avvengono sicuramente dopo i due start. Visto che non hai considerato alcuna forma di sincronizzazione, NON è affatto garantito che il thread lanciato "veda" le modifiche a runFlag (fatte nel EDT) dopo il suo avvio!
  • Re: Thread che funzionano solo con le println

    Caro andbin aspetto con ansia maggiori tue informazioni, sai questo era l'esercizio dell'esame di oggi... la professoressa non ci ha mai parlato di event thread dispatcher e robe varie... io ne sono totalmente ignaro... devo approfondire molto sicuramente perchè ho fatto poco e niente sulle applicazioni grafiche in java... percui ti chiedo scusa se ho fatto erroracci, solo che è pura ignoranza... cioè non so cosa ci sia oltre ciò che ho scritto
  • Re: Thread che funzionano solo con le println

    Il problema del runFlag si risolve velocemente. Dal momento che runFlag è solo scritto nel EDT e solo letto dai due thread, allora la variabile runFlag è una buona candidata per essere marcata "volatile":

    private volatile boolean runFlag=false;

    volatile fornisce una importante informazione alla JVM. Così la JVM evita qualunque tipo di ottimizzazione/caching riguardo l'uso di runFlag e garantisce che tutti i thread "vedano" in modo consistente l'ultimo valore scritto.


    Ci sono però altri problemi nel tuo codice.

    1) Il init() della applet NON è invocato nel contesto del EDT ma in un thread specifico del container delle applet. La cosa che generalmente si fa nel init è usare SwingUtilities.invokeAndWait per dispacciare un Runnable nel EDT.
    C'è l'esempio qui sul tutorial ufficiale.

    2) Nel contesto dei tuoi thread vai ad accedere alla interfaccia utente. Sono quei:

    Pow.setText(""+a);
    T.setText(""+Counter);

    Questo non va bene. Ci sono pochissime operazioni sulla UI che sono thread-safe e possono essere fatte da qualunque thread. Quindi tutto il resto dell'accesso alla UI va fatto esclusivamente nel contesto del EDT.
    Quindi in genere si usa SwingUtilities.invokeLater per dispacciare un Runnable nel EDT che fa quelle modifiche.

    3) Un altro punto è "critico". Sincronizzi sul Counter che è un Integer. Siccome fai Counter++ questo porta a fare un auto-unboxing (da Integer a int), incremento e poi auto-boxing (da int a Integer).
    In sostanza ad ogni incremento hai un nuovo oggetto Integer. E visto che Counter è condiviso tra i due thread .... qualche problema c'è sicuramente perché i due thread potenzialmente possono sincronizzare su Integer appunto diversi.
    In ogni caso, evita questo come la peste .... usa un altro oggetto di lock, che sia comune e stabile.
  • Re: Thread che funzionano solo con le println

    Leggerò il tutorial e proverò a modificare il codice lo posterò qui così magari mi dici meglio, va bene?

    ti ringrazio infinitamente per l'aiuto. a tra poco!
  • Re: Thread che funzionano solo con le println

    Dunque, sto studiando l'esempio fatto sulla pagina... mi chiedo però perchè un JPanel debba implementare un ActionListener... puoi spiegarmelo?
  • Re: Thread che funzionano solo con le println

    Cosa ne pensi di questo codice?:
    import javax.swing.*;
    
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.lang.reflect.InvocationTargetException;
    import java.net.MalformedURLException;
    import java.rmi.Naming;
    import java.rmi.NotBoundException;
    import java.rmi.RemoteException;
    
    @SuppressWarnings("serial")
    public class MyApp extends JApplet{
    
    	public void createMyGraphics(){
    		
    		MyPanel newCP= new MyPanel();
    		newCP.setOpaque(true); 
            setContentPane(newCP);        
    	}
    	
    	public void init(){
    		
    		try {
    		
    			SwingUtilities.invokeAndWait(new Runnable(){
    				
    				public void run(){
    				
    					createMyGraphics();
    				}
    			});
    		}catch (InvocationTargetException | InterruptedException e1) {
    		
    			e1.printStackTrace();
    		}
    	}
    }
    
    class MyThread extends Thread{
    	
    	private int Mode;
    	private static volatile boolean runFlag= false;
    	private static final Object locker=new Object(); 
    	private JTextField myTextCounter, myTextPower;
    	private MyInterface myRMIObj;
    	
    	private static int Counter=1;
    	
    	public MyThread(int mode){
    		
    		this.Mode=mode;
    	}
    	
    	public MyThread(int Mode, JTextField myTextCounter, JTextField myTextPower){
    		
    		this.Mode=Mode;
    		this.myTextCounter=myTextCounter;
    		this.myTextPower=myTextPower;
    	
    		if (Mode==2){
    			
    			try {
    				
    				myRMIObj= (MyInterface)Naming.lookup("//localhost:2025/s");
    			}catch (MalformedURLException | RemoteException | NotBoundException e) {
    
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	public void setRun(boolean b){
    		
    		runFlag=b;
    	}
    	
    	private boolean getRun(){
    		
    		return runFlag;
    	}
    	public void run(){
    		
    		while (true){
    			
    			while(getRun()==true){
    						
    				switch(Mode){
    				
    					case 1:
    						
    						synchronized(locker){
    								
    							Counter++;
    						}
    						break;
    						
    					case 2:
    						
    						synchronized(locker){
    							
    							
    							try {
    								
    								int a = myRMIObj.pow(Counter);
    								
    								try {
    									
    									SwingUtilities.invokeAndWait(new Runnable(){
    										
    										public void run(){
    										
    											myTextCounter.setText(""+Counter);
    											myTextPower.setText(""+a);
    										}
    									});
    								}catch (InvocationTargetException | InterruptedException e1) {
    								
    									e1.printStackTrace();
    								}
    							}
    							catch (RemoteException e) {
    								// TODO Auto-generated catch block
    								e.printStackTrace();
    							}
    						}
    						break;
    						
    					default:
    				}
    				try {
    					sleep(100);
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
    
    
    @SuppressWarnings("serial")
    class MyPanel extends JPanel{
    	
    	private JPanel p1,p2;
    	private JTextField T,Pow;
    	private JButton Start,Stop;
    	
    	MyThread[] Threads= new MyThread[2];
    	
    	public MyPanel(){
    		
    		setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
    		p1=new JPanel();
    		T= new JTextField("1",10);
    		Pow=new JTextField("1",10);
    		p1.add(T);
    		p1.add(Pow);
    		p2=new JPanel();
    		Start=new JButton("Start");
    		Stop=new JButton("Stop");
    		p2.add(Start);
    		p2.add(Stop);
    		add(p1);
    		add(p2);
    		
    		Threads[0]=new MyThread(1);
    		Threads[1]=new MyThread(2,T,Pow);
    		Threads[0].start();
    		Threads[1].start();
    		
    		Start.addActionListener(new ActionListener(){
    			
    			public void actionPerformed(ActionEvent e){
    				
    				Threads[0].setRun(true);
    			}
    		});
    		
    		Stop.addActionListener(new ActionListener(){
    			
    			public void actionPerformed(ActionEvent e){
    				
    				Threads[0].setRun(false);
    			}
    		});
    	}
    }
Devi accedere o registrarti per scrivere nel forum
6 risposte