Как синхронизировать доступ к списку массивов, доступ к которому осуществляется несколькими потоками? - PullRequest
2 голосов
/ 10 ноября 2011

У меня есть ArrayList, который нужно читать и записывать из нескольких компонентов моего графического интерфейса.Я резко сократил объем кода, чтобы попытаться проиллюстрировать проблему в этом кратком фрагменте кода ниже.

В родительском кадре может быть несколько внутренних кадров, и каждому внутреннему кадру потребуется собственный экземпляр этого ArrayList.,Однако всем подкомпонентам определенного внутреннего фрейма потребуется доступ к одному и тому же экземпляру этого ArrayList, так что добавления и удаления сохраняются в одном истинном ArrayList для конкретного внутреннего фрейма.Для этого примера все данные в ArrayList должны быть в памяти.Однако позже я добавлю код для обновления файла постоянных данных при каждом изменении в памяти.

Вот мой сокращенный сегмент кода.Может кто-нибудь показать мне, как изменить этот код, чтобы он дал мне доступ на чтение / запись, который я ищу?Также приветствуются любые ссылки на соответствующие статьи.

ParentFrame.java:

package testGlobalArrayList;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Panel;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JTabbedPane;
import java.util.*;

public class ParentFrame extends JFrame{
private static final long serialVersionUID = 1L;
JLayeredPane desktop;
JInternalFrame internalFrame;

public ParentFrame() {
    super("parent frame");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setPreferredSize(new Dimension(600, 300));
    Panel p = new Panel();
    this.add(p, BorderLayout.SOUTH);
    desktop = new JDesktopPane();
    this.add(desktop, BorderLayout.CENTER);
    this.pack();
    this.setSize(new Dimension(600, 300));
    this.setLocationRelativeTo(null);
    final int DELTA = 40;
    int offset = DELTA;
        int ifWidth = 400;
        int ifHeight = 200;
        internalFrame = new JInternalFrame("internal frame", true, true, true, true);
        internalFrame.setLocation(offset, offset);
        offset += DELTA;

        JTabbedPane jtp = createTabbedPane();
        internalFrame.add(jtp);

        // want to make this ArrayList read/write accessible to every GUI component below this level            
        ArrayList<Integer> myArrayList= new ArrayList<Integer>();
        myArrayList.add(8);
        myArrayList.add(6);
        myArrayList.add(7);

        desktop.add(internalFrame);
        internalFrame.pack();
        internalFrame.setSize(new Dimension(ifWidth,ifHeight));
        internalFrame.setVisible(true);
    }
private JTabbedPane createTabbedPane() {
    JTabbedPane jtp = new JTabbedPane();
    jtp.setMinimumSize(new Dimension(600,300));
    createTab(jtp, "Tab1");
    createTab(jtp, "Tab2");
    return jtp;
    }
private void createTab(JTabbedPane jtp, String s) {
    if(s=="Tab1"){
        TestGUI myTimeSeriesGUI = new TestGUI();
        jtp.add(s,myTimeSeriesGUI);
    }
    else{jtp.add(s, new JLabel("TabbedPane " + s, JLabel.CENTER));}
    }
public static void main(String args[]) {
    ParentFrame myParentFrame = new ParentFrame();
    myParentFrame.setVisible(true);
    }
}

TestGUI.java:

package testGlobalArrayList;

import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.util.ArrayList;
import javax.swing.Box;

public class TestGUI extends JPanel{

TestGUI(){
    Box verticalBox = Box.createVerticalBox();
    verticalBox.add(new TestPanel());
    verticalBox.add(new TestPanel());
    verticalBox.add(new TestPanel());
    this.add(verticalBox, BorderLayout.CENTER);
}
void anotherMethod(){
    // want to be able to add or delete records to same ArrayList here
    myArrayList.add(5);
    myArrayList.add(3);
    myArrayList.add(0);
    myArrayList.add(9);
}
}

TestPanel.java:

package testGlobalArrayList;

import java.awt.Color;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.border.EtchedBorder;

public class TestPanel extends JPanel {
public TestPanel (){
    this.setBackground(getRandomColor());
    this.setBorder( new EtchedBorder() );
    this.setSize(150,20);
}
void anotherMethod(){
    //want to be able to add or delete records from same ArrayList here
    myArrayList.remove(1);
    myArrayList.remove(2);
    myArrayList.remove(3);
}
    private static Color getRandomColor(){
    Random rand = new Random();
    float r = rand.nextFloat();
    float g = rand.nextFloat();
    float b = rand.nextFloat();
    Color randomColor = new Color(r, g, b);
        return randomColor;
    }
}

Ответы [ 4 ]

1 голос
/ 10 ноября 2011

Вы можете использовать шаблон локатора службы (который также может помочь вам с требованием сохранения на диске).

Что-то вроде

public ServiceLocator() {
  private static ArrayHandler handler=new ArrayHandler();

  public static IArrayHandler getArrayHandler() {
    return handler;
  }

}

Затем вы можете создать ArrayHandler для обработкии отслеживание ваших массивов.Таким образом, в вашем коде вы могли бы получить свой массив с чем-то вроде:

ServiceLocator.getArrayHandler().getArray("myarray");

Таким образом, вам не нужно передавать параметры и изменять сигнатуры методов или конструкторов, когда вам нужно «больше никаких переменных».Во всяком случае, это шаблон, который мне нравится и чувствую себя комфортно.YMMV.Приветствия.

1 голос
/ 10 ноября 2011

Вам необходимо использовать контроллер для поддержки такого рода ресурсов.Для Java-интерфейсов вы можете использовать контроллер, доступ к которому осуществляется с помощью одноэлементного метода в любое время, когда вам это нужно.Это должно действовать как гаишник для вашего приложения.

1 голос
/ 10 ноября 2011

передать массив в конструкторах (и сделать его полем)

public class ParentFrame extends JFrame{
    private static final long serialVersionUID = 1L;
    JLayeredPane desktop;
    JInternalFrame internalFrame;
    private List<Integer> myArrayList;

    public ParentFrame() {
        super("parent frame");
        myArrayList= new ArrayList<Integer>();
        myArrayList.add(8);
        myArrayList.add(6);
        myArrayList.add(7);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setPreferredSize(new Dimension(600, 300));
        Panel p = new Panel();
        this.add(p, BorderLayout.SOUTH);
        desktop = new JDesktopPane();
        this.add(desktop, BorderLayout.CENTER);
        this.pack();
        this.setSize(new Dimension(600, 300));
        this.setLocationRelativeTo(null);
        final int DELTA = 40;
        int offset = DELTA;
        int ifWidth = 400;
        int ifHeight = 200;
        internalFrame = new JInternalFrame("internal frame", true, true, true, true);
        internalFrame.setLocation(offset, offset);
        offset += DELTA;

        JTabbedPane jtp = createTabbedPane();
        internalFrame.add(jtp);




        desktop.add(internalFrame);
        internalFrame.pack();
        internalFrame.setSize(new Dimension(ifWidth,ifHeight));
        internalFrame.setVisible(true);
    }


    private void createTab(JTabbedPane jtp, String s) {
        if(s=="Tab1"){
            TestGUI myTimeSeriesGUI = new TestGUI(myArrayList);
            jtp.add(s,myTimeSeriesGUI);
        }
        else{jtp.add(s, new JLabel("TabbedPane " + s, JLabel.CENTER));}
    }
}

TestGui становится

public class TestGUI extends JPanel{
private List<Integer> myArrayList;

TestGUI(List<Integer> myArrayList){
    Box verticalBox = Box.createVerticalBox();
    verticalBox.add(new TestPanel(myArrayList));
    verticalBox.add(new TestPanel(myArrayList));
    verticalBox.add(new TestPanel(myArrayList));
    this.add(verticalBox, BorderLayout.CENTER);
    this.myArrayList = myArrayList;
}
void anotherMethod(){
    // want to be able to add or delete records to same ArrayList here
    myArrayList.add(5);
    myArrayList.add(3);
    myArrayList.add(0);
    myArrayList.add(9);
}

и TestPanel

public class TestPanel extends JPanel {
private ArrayList<Integer> myArrayList;
public TestPanel (ArrayList<Integer> myArrayList){
    this.setBackground(getRandomColor());
    this.setBorder( new EtchedBorder() );
    this.setSize(150,20);
    this.myArrayList = myArrayList;
}
void anotherMethod(){
    //want to be able to add or delete records from same ArrayList here
    myArrayList.remove(1);
    myArrayList.remove(2);
    myArrayList.remove(3);
}
1 голос
/ 10 ноября 2011

Вам необходимо передать ссылку на глобальный список (или объект, инкапсулирующий этот глобальный список) для каждого из компонентов.Передать его в своем конструкторе - это самый простой путь:

ParentFrame.java:

    List<Integer> myArrayList= new ArrayList<Integer>();
    myArrayList.add(8);
    myArrayList.add(6);
    myArrayList.add(7);

    JTabbedPane jtp = createTabbedPane(myArrayList);
    internalFrame.add(jtp);

...

private JTabbedPane createTabbedPane(List<Integer> list) {
    JTabbedPane jtp = new JTabbedPane();
    jtp.setMinimumSize(new Dimension(600,300));
    createTab(jtp, "Tab1", list);
    createTab(jtp, "Tab2", list);
    return jtp;
}
private void createTab(JTabbedPane jtp, String s, List<Integer> list) {
    if ("Tab1".equals(s)){
        TestGUI myTimeSeriesGUI = new TestGUI(list);
        ...

TestGUI.java:

private List<Integer> list;
TestGUI(List<Integer> list) {
    this.list = list;
    ...
...