gpt4 book ai didi

java - 如何使用 volatile 标志仅为最后一个 Thread 实例继续运行 run 方法

转载 作者:行者123 更新时间:2023-12-03 12:58:38 26 4
gpt4 key购买 nike

我使用了变量 exit作为一个 volatile boolean 标志,在我的 Runnable 中暂停 run 方法的执行。 exit变量在我的 Activity 类中定义:

private volatile boolean exit = false;

在按钮单击事件上,我使用以下 Runnable 执行新线程的实例化:
class CounterRunnable implements Runnable {

private Menu menu;

public CounterRunnable(Menu menu) {
this.menu = menu;
}

@Override
public void run() {
int i = 10;
while(!exit) {
if (i > 0) {

final int finalI = i;
runOnUiThread(new Runnable() {
@Override
public void run() {
MenuItem counterMenuItem = menu.findItem(R.id.menu_counter);
counterMenuItem.setTitle(Integer.toString(finalI));
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
i--;
Log.d("Thread name: ", Thread.currentThread().getName() + " i: " + i);
if (i == 0) { break; }
}

scanning = false;
bluetoothAdapter.stopLeScan(LeScanCallback);
invalidateOptionsMenu();

}

private void stop() {
exit = true;
}

public void start() {
exit = false;
}
}

当用户单击按钮进行扫描时,此类 runnable 的实例将传递给新的线程实例。该应用程序用于扫描蓝牙设备。
当点击扫描按钮时,它开始从 10 到 0 倒计时。
用户可以选择通过按下另一个停止按钮来停止扫描,每次按下停止然后再次启动时,我都会使用上面定义的 runnable 实例化新线程实例。
所以这是我实例化新线程的代码:
counterRunnable = new CounterRunnable(menu);
if (!scanning) {
counterRunnable.stop();
} else {
counterThread = new Thread(counterRunnable);
counterThread.start();
counterRunnable.start();
}
scanning如果用户单击了扫描,则变量设置为 true,如果用户单击停止,则变量设置为 false。
当用户由于某种原因多次点击停止和扫描按钮并且速度太快时,会产生大量线程。

如何只允许线程的最后一个实例访问 run 方法并终止所有先前的线程?

最佳答案

加入当前如何counterThread在开始下一个新线程之前。

当用户点击停止按钮时,我们可以停止并加入当前counterThread阻止单击事件处理(主线程)直到当前 counterThread停止(仅几毫秒)。

然后我们可以处理传入的开始按钮点击,并在我们完全停止前一个线程后启动一个新线程。

这是一个例子。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private final static String LOG_TAG = "multithreadmenuupdate";

private Button mStartButton;
private Button mStopButton;
private Menu mMainMenu;
private CounterThread mCounterThread;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Initialize member fields
mStartButton = findViewById(R.id.startButton);
mStopButton = findViewById(R.id.stopButton);
mMainMenu = null;
mCounterThread = null;

// Set click listeners for buttons
mStartButton.setOnClickListener(this);
mStopButton.setOnClickListener(this);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
mMainMenu = menu;
getMenuInflater().inflate(R.menu.main, mMainMenu);
// must return true for the menu to be displayed
return true;
}

@Override
public void onClick(View v) {
switch(v.getId()) {

// Start button clicked?
case R.id.startButton:
// Thread is already running?
if(null != mCounterThread && !mCounterThread.isStopped().get()) break;

mCounterThread = new CounterThread(mMainMenu);
mCounterThread.start();
break;

// Stop button clicked?
case R.id.stopButton:
// No thread?
if(null == mCounterThread) break;

// Interrupt thread to stop
mCounterThread.interrupt();
try {
// Wait until current thread stops
mCounterThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}

class CounterThread extends Thread {

private static final int COUNT_DOWN_START = 10;
private Menu mMenu;
// Indicates if thread is being stopped
// Initially true because the thread is in stopped state
private final AtomicBoolean mIsStopped = new AtomicBoolean(true);

public CounterThread(Menu menu) {
mMenu = menu;
}

@Override
public void run() {
int countDownValue = COUNT_DOWN_START;

// Is not stopped?
while(!mIsStopped.get()) {

// Count down finished?
if(countDownValue == 0) break; // stop thread

// Update menu item with count down value
updateMenuItem(countDownValue);

logThreadMenuUpdate(countDownValue);

// Wait for 1 sec
try {
Thread.sleep(1000); // 1000ms = 1s
} catch(InterruptedException e) {
// Thread has been interrupted to stop?
if(mIsStopped.get()) break; // stop thread
}

// Count down
countDownValue--;
}
}

@Override
public synchronized void start() {
// Change to false allowing thread to run
mIsStopped.set(false);
super.start();
}

@Override
public void interrupt() {
// Thread is being interrupted to stop
// Change to true for thread to stop
mIsStopped.set(true);
super.interrupt();
}

public AtomicBoolean isStopped() {
return mIsStopped;
}

private void updateMenuItem(final int countDownValue) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mMenu.findItem(R.id.menu_counter).setTitle(Integer.toString(countDownValue));
}
});
}

private void logThreadMenuUpdate(int countDownValue) {
StringBuilder str = new StringBuilder();
str.append("Thread name: ").append(Thread.currentThread().getName());
str.append(" - ").append(countDownValue);

Log.d(LOG_TAG, str.toString());
}
}
}

在上面的例子中,我替换了你的 CounterRunnableCounterThread 一起上课.

您可以找到 MainActivity执行也。

因为我已经添加了 Activity 实现,所以我也会添加 Activity 布局和菜单资源 XML。

res/layout/activity_main.xml

<ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:id="@+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/stopButton" />

<Button
android:id="@+id/stopButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/startButton"
app:layout_constraintEnd_toEndOf="parent" />

</ConstraintLayout>

资源/菜单/main.xml

<menu>
<item
android:id="@+id/menu_counter"
android:title="Counter"
app:showAsAction="always" />
</menu>

这是我的示例 Activity 的屏幕截图。
enter image description here

我使用物理设备对此进行了测试,方法是在开始和停止按钮之间快速点击和切换。看起来它运作良好。

关于java - 如何使用 volatile 标志仅为最后一个 Thread 实例继续运行 run 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61565583/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com