我正在启动十个线程来更新十个进度条。
完成栏应该需要五秒钟。
仅启动一个线程时,它将在五秒钟内完成。
当启动所有十个线程时,它们异步更新,并在五秒钟内完成。
是否有可能以更有效的方式完成此任务,以便在十秒钟之内完成所有十个进度条?
这是MainActivity.java
package com.google.example;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
ArrayList<ProgressBar> bars = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for(int i = 0; i < 10; i++){
int id = getResources().getIdentifier("b" + (i+1), "id", getPackageName());
bars.add((ProgressBar) findViewById(id));
}
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int num = 10;
for(int i = 0; i < num; i++){
MyRunnable runnable = new MyRunnable(bars.get(i));
Thread thread = new Thread(runnable);
thread.start();
}
}
});
}
class MyRunnable implements Runnable{
ProgressBar bar;
MyRunnable(ProgressBar b){
bar = b;
}
@Override
public void run() {
int progress = 0;
long previous = 0;
while(progress < 100) {
long time = System.currentTimeMillis();
if (time != previous && time % 50 == 0) {
progress++;
bar.setProgress(progress);
previous = time;
}
}
}
}
}
这是activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"/>
<ProgressBar
android:id="@+id/b1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
<ProgressBar
android:id="@+id/b2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
<ProgressBar
android:id="@+id/b3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
<ProgressBar
android:id="@+id/b4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
<ProgressBar
android:id="@+id/b5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
<ProgressBar
android:id="@+id/b6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
<ProgressBar
android:id="@+id/b7"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
<ProgressBar
android:id="@+id/b8"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
<ProgressBar
android:id="@+id/b9"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
<ProgressBar
android:id="@+id/b10"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"/>
</LinearLayout>
编辑:如@ greeble31所建议,我通过将MyRunnable更改为
解决了该问题。class MyRunnable implements Runnable{
ProgressBar bar;
MyRunnable(ProgressBar b){
bar = b;
}
@Override
public void run() {
int progress = 0;
long hack = System.currentTimeMillis();
while(progress < 100) {
progress = (int) ((System.currentTimeMillis() - hack) / 50);
bar.setProgress(progress);
}
}
}
答案 0 :(得分:0)
由于1个线程需要5秒钟,而且我怀疑您的设备有10个内核(由于这似乎是平板电脑,所以大概是4个内核中的2个),因此您不会在5秒内完成全部10个内核。如果您执行的线程/条数与内核数一样多,则应在大约5秒钟内完成。如果您使用的线程多于内核,则线程肯定必须共享内核才能完成工作,这将花费更长的时间(但比同步处理的时间要少得多)。即使将线程数与内核进行匹配,也无法保证您可以不间断地访问应用程序中的所有内核-仍然需要运行整个操作系统和后台任务。
由于1个线程需要5秒钟,所以同步10个线程需要50秒钟。 10线程中的6到7秒相当不错。
答案 1 :(得分:0)
正如@DavisHerring在评论中提到的,这(几乎全部)是由于MyRunnable.run()
中遗漏了Millis。您的代码假定循环将“看到” System.currentTimeMillis()
的完全顺序的返回值。
您可能会认为,由于循环是全速运行的,因此毫无疑问,它可以每毫秒多次调用System.currentTimeMillis()
,因此很可能不会丢失任何循环。但是,然后,您拥有的线程多于核心,因此很显然,某些线程必须先抢占一部分时间。
此外,在任何抢占式多任务操作系统上,不能保证任何特定线程将在任何特定时间执行。
因此,如果给定线程在短时间内停止执行,则很容易错过50的倍数。例如,其中一个线程可以从System.currentTimeMillis()
中“看到”以下返回值:
1546215544594
1546215544594
1546215544594
1546215544594 <-- thread is unscheduled here, causing a 23ms gap
1546215544617
1546215544617
1546215544617
1546215544617
建议的修补程序
而不是试图抓住每个毫,而是在开始时花一些时间。然后,使progress
等于(经过的时间)/ 50:
progress = (int) ((System.currentTimeMillis() - hack) / 50);
bar.setProgress(progress);
顺便说一句:System.currentTimeMillis()
不能保证返回单调递增的结果(有关替代方法,请参见System.uptimeTimeMillis()
),但是对于您的特定问题,这可能没什么大问题。