简体   繁体   中英

Race condition in the Service(Android) (Too many threads)

I don't know why, but this function is going in the loop under Timer, user specifies how long he wants to wait in between the updates. Somehow the function halts (hangs) on the part, where "System.out.println("checking to add a new comment");". The interesting thing is that this code runs few times before the whole application freezes, so it doesn't have any errors

public ArrayList<String> newComments = new ArrayList<String>();
private ArrayList<String> downloadedComments = new ArrayList<String>();

 onStart(){
    if (receivedComments != null) {fthread
                for (int i = 0; i < receivedComments.size(); i++) {
                    if (newComments.contains(receivedComments.get(i))) {
                        System.out.println("Contains.");
                        newComments.remove(receivedComments.get(i));
                    }
                }
            }
    }

private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {

        System.out.println("got msg");
        switch (msg.what) {
        case 1:
            int add = 0;
            System.out.println("start filling the comments");
            for (int i = 1; i < comments.size(); i++) {
                newComment = comments.get(i).text();
                // System.out.println(newComment);
                System.out.println("checking to add a new comment");
                if (!downloadedComments.contains(newComment)) {
                    newComments.add(newComment);
                    System.out.println("additing");
                    downloadedComments.add(newComment);
                    System.out.println("added");
                    add++;
                    // System.out.println("New comments");
                    // System.out.println(newComments);
                }
                // downloadedComments.add(newComment);
            }

            // System.out.println(add);

            break;

        case 2:
            System.out.println("time refresh");
            timeUpdate.scheduleAtFixedRate(new UpdateGui(context,
                    appWidgetManager), 1, 3000);
        }
    }
};

UpdateGUI class

private class UpdateGui extends TimerTask {
        Context context;

        public UpdateGui(Context context, AppWidgetManager appWidgetManager) {
            this.context = context;
        }

        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                for (int i = 0; i < newComments.size(); i++) {
                    try {
                        System.out.println("sleeping");
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    if (newComments.size() > 0) {
                        notificationView.setViewVisibility(
                                R.id.widget_notificationtext,
                                LinearLayout.VISIBLE);
                        notificationView.setTextViewText(
                                R.id.widget_notificationtext,
                                String.valueOf(newComments.size()));
                    } else {
                        notificationView.setViewVisibility(
                                R.id.widget_notificationtext,
                                LinearLayout.INVISIBLE);
                    }
                    if (newComments.size() != 0) {
                        remoteViews.setTextViewText(R.id.widget_text,
                                newComments.get(i));
                    } else {
                        remoteViews.setTextViewText(R.id.widget_text,
                                "No unread comments");
                    }
                    appWidgetManager.updateAppWidget(thisWidget, remoteViews);
                    appWidgetManager.updateAppWidget(thisWidget,
                            notificationView);
                }
try {
                        System.out.println("sleeping");
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
        }

    }

Since I am waiting every time 3 seconds to update my GUI from the thread, i did not consider what to do when there is nothing to update it with, so the code is being executed at once, but now i added a three seconds delay there as well and everything works just fine. I know that this is not the best design of the application, but i could not come up with anything more eficient than this for now. This was a typical race condition during the update when there is nothing to update, so a simple sleep would help

I'd bet a good amount that this is basically a race condition issue. You are using a bunch of different threads (UI, Timer, Handler, and possibly more). ArrayList is not a synchronized or thread safe class, which means that it's entirely possible that downloadedComments is getting updated while at the same time .contains() is running, causing the internal loop to run basically forever. If you are not passing the data to the various targets (thus ensuring that nothing is being modified in two places), you will have to wrap the accesses in synchronized blocks to prevent concurrent access.

Note that you can get a synchronized version of the list thus:

List list = Collections.synchronizedList(new ArrayList(...));

Synchronization of every method has performance implications. That may not matter for you, though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM