简体   繁体   English

如何同步对多个线程访问的数组列表的访问?

[英]How do I synchronize access to an array list accessed by multiple threads?

I have an ArrayList that needs to be read from and written to from multiple components of my GUI. 我有一个ArrayList,它需要从我的GUI的多个组件中读取和写入。 I have drastically reduced the amount of code to try to illustrate the problem in this concise code segment below. 我已经大大减少了代码量,以尝试在下面的简洁代码段中说明问题。

The parent frame might have a number of internal frames, and each internal frame will need its own instance of this ArrayList. 父框架可能具有许多内部框架,并且每个内部框架将需要其自己的ArrayList实例。 However, all of the subcomponents of a specific internal frame will need access to the same instance of this ArrayList, so that additions and deletions are maintained in one true ArrayList for the specific internal frame. 但是,特定内部框架的所有子组件都需要访问此ArrayList的相同实例,以便在特定内部框架的一个真实ArrayList中维护添加和删除。 For this example, all the data in the ArrayList needs to be in memory. 对于此示例,ArrayList中的所有数据都必须在内存中。 However, I will later add code to update a persistent data file every time a change is made in memory. 但是,稍后我将添加代码以在每次更改内存时更新持久性数据文件。

Here is my reduced code segment. 这是我减少的代码段。 Can anyone show me how to change this code so that it gives me the read/write access that I seek? 谁能告诉我如何更改此代码,以便为我提供所寻求的读/写访问权限? Also, any links to relevant articles would be appreciated. 此外,任何与相关文章的链接都将不胜感激。

ParentFrame.java: 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: 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: 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;
    }
}

You need to pass a reference to the global list (or to an object encapsulating this global list) to each of the components. 您需要将对全局列表(或封装此全局列表的对象)的引用传递给每个组件。 Passing it in their constructor is the easiest way to go: 在构造函数中传递它是最简单的方法:

ParentFrame.java: 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: TestGUI.java:

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

You need to use a controller to maintain these kinds of resources. 您需要使用控制器来维护这些资源。 For java UIs you can use a controller that you access through a singleton method anytime you need it. 对于Java UI,您可以随时使用通过单例方法访问的控制器。 This should act as the traffic cop to your app. 这应该充当您应用程序的访问量。

pass the arraylist along in the constructors (and make it a field) 在构造函数中传递arraylist(并使其成为字段)

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 becomes 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);
}

and TestPanel 和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);
}

You could use Service locator pattern (which might also help you with the requirement of persisting to disk). 您可以使用服务定位器模式(也可以帮助您持久存储到磁盘)。

Something like 就像是

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

  public static IArrayHandler getArrayHandler() {
    return handler;
  }

}

Then you can create your ArrayHandler to handle creating and keeping track of your arrays. 然后,您可以创建ArrayHandler来处理数组的创建和跟踪。 So in your code you could get your array with something like: 因此,在您的代码中,您可以使用以下内容获取数组:

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

This way you don't need to pass parameters around and change method or constructor signatures when you need "no more variable". 这样,当您不需要“更多变量”时,您无需传递参数并更改方法或构造函数签名。 Anyway, this is a pattern I like and feel comfortable with. 无论如何,这是我喜欢并感到满意的模式。 YMMV. 因人而异。 Cheers. 干杯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何正确同步多个线程正在访问的列表? - How to properly synchronize a list being accessed by multiple threads? 如何同步缓存列表访问 - How do I synchronize cache list access Java如何正确同步多个线程上的arraylist? - Java how do I properly synchronize an arraylist over multiple threads? 如何同步在工厂设计模式(单个实例)中由多个线程访问的List变量 - How can I synchronize a List variable, that is accessed by multiple thread In a Factory design pattern (Single Instance) 如果我有多个要插入MySQL的线程,是否需要同步? - Do I need to synchronize if I have multiple threads that will insert to MySQL? 我是否需要在多个线程之间同步 getter 函数? - Do I need to synchronize a getter function between multiple threads? Java-如何在1个列表上同步2个线程? - Java - How To Synchronize 2 Threads On 1 List? ArrayList,线程和同步 - 同步如何准确地为多个线程工作 - ArrayList, Threads and synchronize - how does synchronize exactly work for multiple threads 我是否需要同步访问仅由一个线程修改的List? - Do I need to synchronize access to a List that is only modified by one thread? 如何在EhCache中同步多个线程的动作? - How to synchronize action of multiple threads in EhCache?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM