SwingWorker中的Threadsafety - 以线程安全方式更新JTable

时间:2016-04-02 13:54:15

标签: java thread-safety swingworker

我有一个旅行优惠清单,我从XML文件中读取并解析,并使用JTable将它们添加到我的GUI中。我还有一些更新功能(间隔和即时点击),只要新的商品被添加到XML,就会更新GUI。我的目标是以线程安全的方式在GUI中添加商品。

这是类(UpdateData.java),我使用Swingworker执行doInBackground(),更关注安全性。 (如果有人有兴趣深入了解,其他类也会在下面显示)可以使用SwingUtilities.invokeLater()来使其线程安全吗?重写Swingworkers done(),execute()和process()会以某种方式帮助实现安全吗?在那种情况下怎么样? (新手在线程编程)(如果有人有兴趣深入了解,下面给出其他课程)。一些帮助/反馈将受到高度赞赏。

类: UpdateData.java

public class UpdateData extends SwingWorker<Integer, Integer> {

    private ArrayList<RawTravelData> listOfOffer;
    private TravelData offerData;
    private XMLReader parseData;
    //the controller
    private ControlUpdate updtController;

    //constructor
    public UpdateData(TravelData o, ControlUpdate offerController) {
        updtController = offerController;
        parseData = new XMLReader();
        offerData = o;
    }

    @Override
    protected Integer doInBackground() throws Exception {
        listOfOffer = parseData.fetchData();
        offerData.setData(listOfOffer);
        updtController.setOfferArray(listOfOffer);

        return null;
    }

}

类: RawTravelData.java

public class RawTravelData {

    private String destination = "";
    private String travelDate = "";
    private int currPrice;

    //empty constructor
    public RawTravelData() {

    }

    //setters ad getters for destination, travel date and currprise

}

分类: TravelData.java

public class TravelData extends AbstractTableModel {

    //the table header strings
    private String[] colNames = { "Destination", "Date", "Price", "Details" };
    private static final long serialVersionUID = 1L;
    //arraylist of the offer data
    private ArrayList<RawTravelData> offerList;

    //constructor
    public TravelData(ArrayList<RawTravelData> rtd) {
        offerList = rtd;
    }

    //second constructor to create empty list
    public TravelData() {
        offerList = new ArrayList<RawTravelData>();
    }

    //add the list
    public void setData(ArrayList<RawTravelData> o) {
        offerList = o;
        this.fireTableDataChanged();
    }

    //get the offer list
    public ArrayList<RawTravelData> getOfferList() {
        return offerList;
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
        case 0:
            return String.class;
        case 1:
            return Integer.class;
        case 2:
            return String.class;
        case 3:
            return String.class;

        default:
            break;
        }
        return String.class;
    }

    @Override
    public int getColumnCount() {
        return colNames.length;
    }

    @Override
    public int getRowCount() {
        return offerList.size();
    }

    @Override
    public Object getValueAt(int arg0, int arg1) {
        switch (arg1) {
        case 0:
            return offerList.get(arg0).getDestination();
        case 1:
            return offerList.get(arg0).getPrice();
        case 2:
            return offerList.get(arg0).getTravelDate();
        case 3:
            return "Details";
        default:
            break;
        }
        return "null";
    }

    @Override
    public String getColumnName(int col) {
        return colNames[col];
    }

}

类: XMLReader.java

public class XMLReader {

    //Method to fetch and read all the data from the XML file
    public ArrayList<RawTravelData> fetchData() {

       //parse data and return as arraylist of offers

        return arrayOfOffer;
    }
}

类: ControlUpdate.java

//This class is responsible for controlling the updating of the offer data in the background
public class ControlUpdate {

    private TablePanel tablePane;
    private ArrayList<RawTravelData> offerArray;
    //..

    //Constructor
    public ControlUpdate(TablePanel tablePane) {
        settingsVal = new SaveSettings();

        this.tablePane = tablePane;
        tablePane.getOfferTable().addMouseListener(
                new TableSortListener(tablePane.getOfferTable(), this));
        runUpdateTask();
        setUpdateInterval(settingsVal.readSettings());
    }


    //run the updates
    private void runUpdateTask() {
        //used Timer and ScheduledThreadPool
    }

    //get the table panel
    public TablePanel getTablePanel() {
        return tablePane;
    }

    //setting the list to a new offer list for the updater
    public void setOfferArray(ArrayList<RawTravelData> rtd) {
        offerArray = rtd;
    }

}

1 个答案:

答案 0 :(得分:1)

组件及其模型的所有修改都需要在AWT事件派发线程中执行,而不是在后台线程中执行。 doInBackground方法的第二行和第三行应移至done方法,is guaranteed to be executed in the AWT event thread

通常情况下,SwingWorker的值类型是您在后台获取的数据。

public class UpdateData
extends SwingWorker<List<RawTravelData>, Integer> {

    // ...

    @Override
    protected List<RawTravelData> doInBackground() throws Exception {
        return parseData.fetchData();
    }

    @Override
    protected void done() {
        try {
            List<RawTravelData> listOfOffer = get();

            offerData.setData(listOfOffer);
            updtController.setOfferArray(listOfOffer);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            // Someone wants us to exit cleanly.
            e.printStackTrace();
        }
    }
}