Op deze website gebruiken we cookies om content en advertenties te personaliseren, om functies voor social media te bieden en om ons websiteverkeer te analyseren. Ook delen we informatie over uw gebruik van onze site met onze partners voor social media, adverteren en analyse. Deze partners kunnen deze gegevens combineren met andere informatie die u aan ze heeft verstrekt of die ze hebben verzameld op basis van uw gebruik van hun services. Meer informatie.

Akkoord

Vraag & Antwoord

Programmeren

java threads

None
13 antwoorden
  • hallo,

    ik heb een vraag i.v.m. threads in java:
    ik zie namelijk niet in dat threads simultaan zijn, ik heb in het boek "java threads" van O' Reilly gelezen.
    in het boek gaven ze een voorbeeld van een text-editor met een autosave mogelijkheid
    zo stond er dat de gebruiker ongestoord zou kunnen blijven verdertypen terwijl de text-editor opslaat.

    maar volgens mij kan dat toch niet, kijk maar is naar de figuur die ik gemaakt heb:
    [img:f18869690e]http://img534.imageshack.us/img534/4451/vraagthreads.png[/img:f18869690e]

    onderaan stellen de 2 rechthoeken mijn programma voor.
    links is het hoofdprogramma, met de code in voor het inlezen van de letters die de gebruiker intypt via het toetsenbord.
    rechts is de thread om periodiek het bestand te gaan opslaan op de harde schijf.

    nu stel dat het programma ingesteld is elke 3 min te gaan opslaan.
    de gebruiker start het programma en begint met typen, tot hiertoe is er nog geen probleem de gebruiker kan rustig doortypen want het hoofdprogramma heeft de cpu helemaal voor zichzelf zie groene pijl.
    maar als de eerste 3 min voorbij zijn treed de save thread in actie, hierdoor word het hoofdprogramma even onderbroken om zodat de save thread de cpu kan bemachtigen zie oranje pijl

    kan iemand mij uitleggen waar ik verkeerd ben?

    Alvast bedankt!:D
  • Je hebt het eigenlijk wel goed begrepen. In het echt zijn threads ook niet simultaan. Dat houdt dus in als hij gaat opslaan kan hij niet gelijk doortypen, maarrrr

    Wanneer je geen multithreading ondersteund, en je wilt opslaan dan gaat hij eerst alle code uitvoeren voor het opslaan, voordat je verder kan typen.

    Bij multithreading, voert hij bijv. de eerste 2 regels code van het opslaan uit, daarna 2 regels van het typen, daarna weer 2 regels code van het opslaan. etc

    oftewel, hij verdeelt het in nog kleinere stukjes ;)
  • de code die is toch al gecompileerd naar een taal die de cpu kan uitvoeren(machinetaal: 10101010)?

    en als een thread in actie komt dan voert hij toch in 1 keer alles uit wat in de
    run() methode staat, in dit geval het opslaan van wat er al getypt is.

    wat ik mij ook afvraag is: stel nu dat je de opslaan thread zou vervangen door een muziekje dat afspeelt tijdens het typen. dan zou het muziekje toch
    haperen wanneer de cpu tekst inleest van het toetsenbord en omgekeerd…?
  • Ik weet niet of je ooit eens met dos gewerkt hebt? Daar had je inderdaad 1 ding te gelijk. Je tikte een commando in en hij verwerkte dat commando. Je kon een nieuw commando pas uitvoeren zodra de oude klaar was.
    Met de komst van moderne besturingssystemen, kan je meerdere dingen tegelijk doen, een muziekje luisteren en ondertussen een word bestand uittypen. Je hebt vaak veel processen 'tegelijk' draaien.

    Dat tegelijk van bijvoorbeeld windows, is eigenlijk ook helemaal niet tegelijk. Dus het proces van het muziek afspelen en het proces van een word bestand uittypen lijken tegelijk te gebeuren maar achter de schermen gebeurd dit om de beurt. Dan even 0,001 sec muziek, dan weer 0,001 sec uittypen. Het wisselt zich zo extreem veel af waardoor het LIJKT alsof het tegelijk gebeurd. Het gaat dus puur om de snelheid.

    Een proces kan bestaan uit 1 of meerdere threads. Het afwisselen van die threads (in het geval als het er meer zijn) gaat precies zo. Het wisselt met zon grote snelheid af als of het lijkt dat het tegelijk gebeurd, maar eigenlijk gaat het steeds om de beurt.

    uiteindelijk wordt een programmeertaal inderdaad in een soort van machinetaal omgezet. Het is niet zo dat het direct 10101 wordt, maar een soort tussenstap. (Bij java werkt het weer wat anders maar dan moet je daar nog maar eens op googelen). Maar uiteindelijk worden die stukken van 10101 verdeelt in verschillende stukken en zo stuk voor stuk afgestuurd op de processor. Je OS regelt dan de volgorde en het multi processing/threading gedeeelte.

    [quote:535d5931db]
    en als een thread in actie komt dan voert hij toch in 1 keer alles uit wat in de run() methode staat, in dit geval het opslaan van wat er al getypt is.
    [/quote:535d5931db]

    Nee dat is dus niet zo. Het kan best zijn dat hij eerst 2 regels uitvoert van het opslaan, dat even op pauze zet, een stukje tekst uittypt en vervolgens de rest van de code uitvoert.

    Als je met multithreading gaat werken is dit ook van groot belang om te beseffen. Het kan dus bijvoorbeeld inhouden dat je threads hebt voor het opslaan en openen van een bestand. Ook al sla je in je code een bestand op voordat je het openen, met threads kan het dus voorkomen dat je het al eerder opent dan je het op opslaat, aangezien je os op het moment van uitvoeren de volgorde gaat bepalen. Wanneer je maar 1 thread hebt, dan kan er niets fout gaat :)

    Is het een beetje duidelijk?
  • nee het is mij nog niet helemaal duidelijk.

    ik heb op internet volgend voorbeeldje gevonden:
    [img:d7ccac14df]http://img834.imageshack.us/img834/3747/counterl.png[/img:d7ccac14df]

    dit is een programma dat gaat tellen van 1 tot 1000
    als je op start drukt dan print hij de getallen af in de textbox
    en als je op stop drukt stop het programma met tellen

    wat ik vreemd vind is het volgend stukje code:
    [code:1:d7ccac14df] btnStart.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
    stop = false;
    Thread t = new Thread() {
    public void run() {
    for (int i = 0; i < 100000; i++) {
    if (stop) break;
    tfCount.setText("" + countValue);
    countValue++;
    try {
    sleep(10);
    } catch (InterruptedException ex) {}
    }
    }
    };
    t.start();
    }
    });[/code:1:d7ccac14df]

    wat ze hier gedaan hebben is de code voor de inhoud van de textbox te veranderen, in een thread gestoken.

    als je dit niet in een thread doet, dan zie je de inhoud van de textbox niet veranderen, dit vind ik wel beetje vreemd als je nu gewoon:


    [code:1:d7ccac14df] for (int i = 0; i < 100000; i++) {
    if (stop) break;
    tfCount.setText("" + countValue);
    countValue++;
    }[/code:1:d7ccac14df]

    dan wordt de for-lus doorlopen en wordt de textbox toch overschreven, niet?

    note: tfCount is een textbox en btnstart is de startknop
    if(stop) is een boolean die die door de stopknop op true word gezet
  • ik zie nergens de declaratie van countValue. Zou je dat stukje ook nog eens kunnen laten zien.

    Je gebruikt een for loopje om de countValue op te hogen en deze vervolgens af te beelden in het tekstveld. Nu zijn er een aantal zaken waarom het niet werkt als je het niet in een aparte thread plaatst.

    1) Wanneer je setText aanroept van je tekstveld, dan wordt de nieuwe tekst nog niet gelijk afgebeeld. Onder water roept java vaak de paint methode aan. Dit zorgt ervoor dat het tekstveld opnieuw 'getekend' wordt en dus met de nieuwe tekst. Op dat moment is je thread al druk bezig met je for loop en wacht dus met de paint aanroepen tot hij klaar is met je loop. (Het zou kunnen dat ik dit fout heb, maar ik ben helaas niet zo heel bekend met de gui van java.) Je kan dus misschien voor de zekerheid na de settext ook even de paint aanroepen.

    2) Ten tweede gaat je loop zo snel naar de 1000 dat hij dit al bereikt heeft voordat jij er erg in hebt. Dus hij zal misschien alleen het getal 1000 tonen. Je zult het optellen dus moeten vertragen. Je kan hiervoor met een timer aan de slag, maar in je voorbeeld pauzeren ze de thread waarin het optellen gebeurd. Door dit pauzeren krijg je main thread ook de kans om paint aan te roepen.

    Normaal gesproken doe je dit gewoon met een timer, maar om threads te tonen doen ze het dus nu met een thread.

    Om weer even over het algemeen over threads te hebben:

    Stel je hebt 2 processen, Word en jouw prog genaamd a1

    word heeft een aantal regels code en a1 ook. Wanneer beiden processen draaien kan het verwerken van hun code er bijvoorbeeld zo uit zien

    word - regel 1
    word - regel 2
    a1 - regel1
    word -regel 3
    a1 - regel 2
    a1 - regel 3


    volledige willekeur dus

    Wanneer a1 nu uit 2 threads bestaat (standaard bestaat het gewoon uit 1) dan kan het bijvoorbeeld zo uit zien

    word - regel 1
    a1 - thread1 - regel 1
    a1 - thread2 - regel 1
    word - regel 2
    word - regel 3
    a1 - thread 2 - regel 2
    a1 - thread 2 - regel 3


    Zoals je ziet hoeft de code van thread 2 helemaal niet te wachten tot de code van thread 1 helemaal is uitgevoerd..

    Als je meer uitleg wilt over het voorbeeld wat je net gaf, moet je even de volledige code geven. (dus een rar bestand ofzo).
  • ik zal mijn vraag anders stellen:
    zo ziet het programma er dus uit als je het opstart hé:

    [img:43bd8eb762]http://img834.imageshack.us/img834/3747/counterl.png[/img:43bd8eb762]

    het is een heel eenvoudig programma, je hebt een startknop en stopknop als je op de startknop drukt dan word een for-lus gestart dat van 1 tot 100000 gaat tellen en drukt die cijfers af in een texkfield.

    wat ze in dit voorbeeld hebben gedaan is de for-lus in aparte thread gestoken om 2 redenen zogenaamd
    1. zodat de teller kan onderbroken worden wanneer je op de stopknop drukt.
    2. zodat het textfield word upgedate met de nieuwe waarde, m.a.w. je ziet de cijfers in het textfield heel snel voorbij flikkeren.

    de eerste reden vind ik logisch, doordat java druk bezig is met de for-lus uit te voeren zou je niet meer kunnen klikken op de stopknop.

    maar de tweede reden vind ik al minder logisch, veronderstel nu even dat je het tellertje niet in een aparte thread plaats.
    dan heeft dat als gevolg dat je niet op de stopknop zal kunnen drukken tot wanneer het tellen is afgelopen, dit vind ik logisch.
    maar dat heeft blijkbaar ook als gevolg dat je de cijfers niet meer ziet voorbij flikkeren in het textfield, hij staat in het begin op 1
    en na enkele seconden wachten staat hij op 100000.
    en het is dit dat ik niet snap: blijkbaar wordt de setText(" ") methode niet meer constant uitgevoerd?
    want ik zie het cijfer in het textfield niet meer meer veranderen behalve dan na die paar seconden.

    nochtans staat deze methode aanroep wel in mijn for-lus.

    stel jij bent java, als er nu word geklikt op de startknop dan krijg jij een melding van een event, je ziet dat de event van de startknop afkomstig is.
    dus je springt meteen naar de actionPerformed(Actionevent evt) methode.
    daarin zie je een for-lus die zegt dat je de code in de for-lus 100000 keer moet uitvoeren.
    oké zeg je ik zal dat doen dus je begint met de eerste keer in de for-lus te gaan. daar zie je plots de volgende methode
    setText(" "+ cijfer) van de klasse JTextField, dus spring je in die methode en voert daar alle instructies uit om het cijfer in het textfield af te printen nadat dit gebeurt is keer je terug en doe je verder met de rest van de for-lus je ziet dat niets meer moet uitgevoerd worden dus je voert de for-lus een tweede keer uit en je doet weer hetzelfde maar dan met het volgende cijfer
    je doet dit 100000 keer en stopt dan.

    weet iemand hoe dit komt?

    dit is de code (met thread):
    [code:1:43bd8eb762]package threads;

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;

    public class UnresponsiveUI extends JFrame {
    private boolean stop = false;
    private JTextField tfCount;
    private int countValue = 1;

    public UnresponsiveUI() { // constructor
    Container cp = this.getContentPane();
    cp.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
    cp.add(new JLabel("Counter"));
    tfCount = new JTextField("" + countValue, 10);
    tfCount.setEditable(false);
    cp.add(tfCount);

    JButton btnStart = new JButton("Start Counting");
    cp.add(btnStart);
    btnStart.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
    stop = false;
    Thread t = new Thread() {
    public void run() {
    for (int i = 0; i < 100000; i++) {
    if (stop) break;
    tfCount.setText("" + countValue);
    countValue++;
    }
    }
    };
    t.start();
    }
    });

    JButton btnStop = new JButton("Stop Counting");
    cp.add(btnStop);
    btnStop.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) { stop = true; }
    });

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setTitle("Counter");
    setSize(300, 120);
    setVisible(true);
    }

    public static void main(String[] args) {
    new UnresponsiveUI();
    }
    } [/code:1:43bd8eb762]

    note: ik heb er is ook een System.out.println(""+countvalue) bij geplaatst, en daar zie je wel de cijfertjes voorbij flitsen…
    heeft iemand hier een uitleg voor? :/
  • zie mijn vorige post hierboven, had mijn vraag nogal slecht geformuleerd :wink:
  • De reden hiervoor staat bij mij 1 in het vorige antwoord, maar ik zal het wat verder toelichten:

    De settext wordt elke keer in de for loop uitgevoerd. Echter zorgt dit er niet voor dat het tekstveld ook met de nieuwe waarde wordt afgebeeld. Om dit voor elkaar te krijgen wordt onder water de paint of repaint methode aangeroepen.

    dus stel een tekstveld bevat de waarde hello, ik roep daarna settext("hello world") aan. Op het moment daarna zie je in het tekstveld nog steeds hello staan. Maar op zon moment realiseert 'java' zich dat het veld zichzelf moet updaten en roept paint of repaint aan. Daarna zie je wel hello wolrd staan.

    In jouw geval, in 1 thread dus, wordt het aanroepen van paint pas gedaan nadat de for loop is voltooid. Na het voltooien van de for loop kan het scherm weer hertekend worden of het tekstveld en dan staat er plots 1000 …

    Door een tweede thread in het leven te roepen wordt de for loop steeds gepauzeerd en krijg de main thread ook de kans om de paint methode aan te roepen.
  • maar als je settext() vervangt door system.out.println()
    dan zie je wel de cijfertjes voorbij flikkeren?

    de methode println() van de outputstream klasse is toch te vergelijken met de settext() van JTextfield klasse?

    nu doe ik countvalue++ hé stel nu dat ik een klasse rekenmachine zou maken en daarin een methode schrijf:

    public int verhoogMetEen(int vorige waarde){
    return vorigewaarde++;
    }

    in de for-lus doe ik dan niet meer countvalue++, maar roep ik de methode: countvalue = rekenmachine.voorhoogMetEen(countvalue);
    dan zou hij countvalue ook alleen maar na de for-lus met 1 mogen verhogen he en dan zou countvalue 2 zijn.
    ik heb dit getest en countvalue is toch 100000 dus in die methode is hij wel alltijd gegaan.
    dat is toch net hetzelfde met die settext() hij gaat in settext() en voert daar de paint() methode uit
    en paint() verandert de inhoud van het textvak
    en dan doet hij weer verder met de for-lus…

    snap je wat ik bedoel? :)

    [code:1:6d24396ddd]package threads;

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;

    public class UnresponsiveUI extends JFrame {
    private boolean stop = false;
    private JTextField tfCount;
    private int countValue = 1;
    private Rekenmachine rek;

    public UnresponsiveUI() { // constructor
    Container cp = this.getContentPane();
    cp.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
    cp.add(new JLabel("Counter"));
    tfCount = new JTextField("" + countValue, 10);
    rek = new Rekenmachine();
    tfCount.setEditable(false);
    cp.add(tfCount);

    JButton btnStart = new JButton("Start Counting");
    cp.add(btnStart);
    btnStart.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
    // Thread t1 = new Thread() {
    // public void run() {
    stop = false;
    for (int i = 0; i < 100000; i++) {
    if (stop)
    break;
    System.out.printf("%s
    ", countValue);
    tfCount.setText("" + countValue);
    countValue = rek.verhoogMetEen(countValue);
    }
    // }
    // };
    // t1.start();
    }
    });

    JButton btnStop = new JButton("Stop Counting");
    cp.add(btnStop);
    btnStop.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
    stop = true;
    }
    });

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setTitle("Counter");
    setSize(300, 120);
    setVisible(true);
    }

    public static void main(String[] args) {
    new UnresponsiveUI();
    }
    }
    [/code:1:6d24396ddd]
  • Ik snap wat je bedoelt, maar zo werkt het niet.

    println.. is simpel weg een methode. Die wordt aangeroepen en print iets op de console. Settext verandert alleen de text attribute van het huidige object en doet verder niets. Een listener luister naar dat text attribute en roept wanneer deze wijzigd een update methode aan, die in ons geval de paint methode zal aanroepen.

    Om in details te treden, die listener is een document listener (even opgezocht in de java api). Deze geeft al aan dat de volgorde wanneer deze een update aanroept volledig willekeurig is, dus net wanneer er tijd voor hem is. Het is dus niet zo dat die text wijzigt en dat dan gelijk de update methode aan wordt geroepen. De for loop wordt afgerond en dan krijg de document listener de tijd om te kijken of er wijzigingen zijn en ze eigen update methode aan te roepen.

    De settext methode: http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/javax/swing/text/JTextComponent.html#setText(java.lang.String)

    En de document listener : http://download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/javax/swing/event/DocumentListener.html
  • ja inderdaad ik begrijp het, bedankt blackhawkdesign!! :P
  • Graag gedaan :)

Beantwoord deze vraag

Dit is een gearchiveerde pagina. Antwoorden is niet meer mogelijk.