服务中的竞争条件(Android)(线程太多)
我不知道为什么,但这个函数在计时器下循环,用户指定他想要在更新之间等待多长时间。不知何故,该函数在“System.out.println(“检查以添加新注释”);”的部分暂停(挂起)。有趣的是,这段代码在整个应用程序冻结之前运行了几次,因此它没有任何错误
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 类
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();
}
}
}
}
因为我每次都等待 3 秒从线程更新我的 GUI,所以我没有考虑在什么时候该做什么没有什么可以更新它,所以代码是立即执行的,但现在我也在那里添加了三秒的延迟,一切都工作得很好。我知道这不是应用程序的最佳设计,但目前我无法想出比这更有效的设计。 这是更新期间没有什么可更新的典型竞争条件,因此简单的睡眠会有所帮助
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我敢打赌这基本上是一个竞争条件问题。您正在使用一堆不同的线程(UI、计时器、处理程序,以及可能更多)。
ArrayList
不是同步或线程安全类,这意味着downloadedComments
完全有可能在 .contains() 运行的同时进行更新,从而导致内部循环基本上永远运行。如果您不将数据传递到各个目标(从而确保两个地方没有任何内容被修改),则必须将访问包装在同步块中以防止并发访问。请注意,您可以获得列表的同步版本,如下所示:
每个方法的同步都会影响性能。不过,这对你来说可能并不重要。
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 thatdownloadedComments
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 insynchronized
blocks to prevent concurrent access.Note that you can get a synchronized version of the list thus:
Synchronization of every method has performance implications. That may not matter for you, though.