Ik heb een Monitor-object gemaakt waarin een ListModel is opgenomen. Dit model wordt door twee threads benaderd om er iets in te stoppen of iets uit te halen. Thread 1 genereert objecten en deze objecten worden in de monitor geplaatst. Thread twee haalt ene object uit de monitor en plaatst hem na behandeling weer terug. Er zijn dus drie methodes, namelijk een generate(Object o), een put(Object o) en een pop() methode, die alle drie gesynchronizeerd zijn. Hieronder een klein stukje code:
Om een indicatie te geven hoe de threads, monitor en GUI met elkaar communiceren, heb ik het volgende schema gemaakt:

De ListModel in de Monitor wordt dus in de GUI weergegeven in een JList. Deze ListModel wordt daarnaast benaderd door thread 1 mbv de 'synchronized boolean generate(Job job)' en door thread 2 mbv de methodes 'synchronized Job pop()' en 'synchronized void put(Job job)'. Dit werkt allemaal prima.
Wat gaat er dan wel fout?
Bij het weergeven van de ListModel gaat het heel af en toe fout. Dit gebeurt vanuit de gui-component, want de fout wordt veroorzaakt bij de ListModel.get(int index) methode. De index komt af en toe buiten zijn bereik:
De enige verklaring die ik kan geven is dat tijdens het refreshen van de JList door Thread 2 een pop wordt gedaan. Daardoor wordt de grootte van de queue 1 object kleiner, waardoor bij het weergeven van het laatste object een IndexOutOfBoundsException optreedt.
Mijn vraag is hoe ik ook het refreshen van de JList kan synchroniseren, zodat op dat moment geen in- of uitvoer op de queue gedaan kan worden?
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| public class Monitor { private ListModel _queue; private boolean _locked; public Monitor() { // initialise components e.d. } // wordt aangeroepen door de GUI component public ListModel getQueue() { return _queue; } // wordt aangeroepen door Thread 1 public synchronized boolean generate(Job job) { { if (!_locked) { _buffer.add(job, calculateIndex(job)); return true; } return false; } // wordt aangeroepen door Thread 2 public synchronized Job pop() { { return _buffer.remove(0); } public synchronized void put(Job job) { // wordt aangeroepen door Thread 2 { _buffer.add(job ,calculateIndex(job))); } ... ... } |
Om een indicatie te geven hoe de threads, monitor en GUI met elkaar communiceren, heb ik het volgende schema gemaakt:
De ListModel in de Monitor wordt dus in de GUI weergegeven in een JList. Deze ListModel wordt daarnaast benaderd door thread 1 mbv de 'synchronized boolean generate(Job job)' en door thread 2 mbv de methodes 'synchronized Job pop()' en 'synchronized void put(Job job)'. Dit werkt allemaal prima.
Wat gaat er dan wel fout?
Bij het weergeven van de ListModel gaat het heel af en toe fout. Dit gebeurt vanuit de gui-component, want de fout wordt veroorzaakt bij de ListModel.get(int index) methode. De index komt af en toe buiten zijn bereik:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 10, Size: 10
at java.util.LinkedList.entry(LinkedList.java:368)
at java.util.LinkedList.get(LinkedList.java:313)
at jobSimulator.monitor.MonitorListModel.getElementAt(MonitorListModel.java:31)
at jobSimulator.monitor.MonitorListModel.getElementAt(MonitorListModel.java:17)
at javax.swing.plaf.basic.BasicListUI.paintCell(BasicListUI.java:182)
at javax.swing.plaf.basic.BasicListUI.paint(BasicListUI.java:287)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:142)
at javax.swing.JComponent.paintComponent(JComponent.java:740)
at javax.swing.JComponent.paint(JComponent.java:1003)
at javax.swing.JComponent.paintWithOffscreenBuffer(JComponent.java:4930)
at javax.swing.JComponent.paintDoubleBuffered(JComponent.java:4883)
at javax.swing.JComponent._paintImmediately(JComponent.java:4826)
at javax.swing.JComponent.paintImmediately(JComponent.java:4633)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:451)
at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:114)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:234)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:110) |
De enige verklaring die ik kan geven is dat tijdens het refreshen van de JList door Thread 2 een pop wordt gedaan. Daardoor wordt de grootte van de queue 1 object kleiner, waardoor bij het weergeven van het laatste object een IndexOutOfBoundsException optreedt.
Mijn vraag is hoe ik ook het refreshen van de JList kan synchroniseren, zodat op dat moment geen in- of uitvoer op de queue gedaan kan worden?