是否可以重写此代码以更好地使用处理器? 我有一个类,它在一个单独的线程中使用固定的周期执行一些任务。有时可以暂停和恢复此过程。目前我正在使用暂停的标志,它工作正常,但这样的循环仍然会在进程暂停时加载处理器。有可能解决这个问题吗?
private boolean mIsCanceled = false;
private boolean mIsPaused = true; // TODO more efficient for processor way of pausing is required
private final Thread mTimerThread = new Thread(new Runnable() {
@Override
public void run() {
while(!mIsCanceled){
try {
Thread.sleep(UPDATE_PERIOD);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!mIsPaused){
doStep();
}
}
}
});
public MyClass(){
mTimerThread.start();
}
private void pause(){
mIsPaused = true;
}
private void resume(){
mIsPaused = false;
}
private void doStep(){
// Some code
}
请提供我的代码的替代实现。
P.S。环境是Android OS 2.2 +
答案 0 :(得分:5)
可用的工具是:
wait
/ notify
- 我们都试图摆脱这个古老的系统。
Semaphore
s - 一旦你的线程抓住它,你持有它直到释放所以再次抓住它不会阻止。这意味着您无法在自己的线程中暂停。
CyclicBarrier
- 每次使用时都必须重新创建。
ReadWriteLock
- 我最喜欢的。您可以让尽可能多的线程暂停您,并且只有在所有线程都调用resume
时才会恢复。如果你愿意,你甚至可以暂停一下。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* PauseableThread is a Thread with pause/resume and cancel methods.
*
* The meat of the process must implement `step`.
*
* You can either extend this and implement `step` or use the factory.
*
* Note that I cannot extend Thread because my resume will clash with Thread's deprecated one.
*
* Usage: Either write a `Stepper` and run it in a `PausableThread` or extend `PausableThread` and call `blockIfPaused()` at appropriate points.
*/
public abstract class PauseableThread implements Runnable {
// The lock.
// We'll hold a read lock on it to pause the thread.
// The thread will momentarily grab a write lock on it to pause.
// This way you can have multiple pausers using normal locks.
private final ReadWriteLock pause = new ReentrantReadWriteLock();
// Flag to cancel the wholeprocess.
private volatile boolean cancelled = false;
// The exception that caused it to finish.
private Exception thrown = null;
@Override
// The core run mechanism.
public void run() {
try {
while (!cancelled) {
// Block here if we're paused.
blockIfPaused();
// Do my work.
step();
}
} catch (Exception ex) {
// Just fall out when exception is thrown.
thrown = ex;
}
}
// Block if pause has been called without a matching resume.
private void blockIfPaused() throws InterruptedException {
try {
// Grab a write lock. Will block if a read lock has been taken.
pause.writeLock().lockInterruptibly();
} finally {
// Release the lock immediately to avoid blocking when pause is called.
pause.writeLock().unlock();
}
}
// Pause the work. NB: MUST be balanced by a resume.
public void pause() {
// We can wait for a lock here.
pause.readLock().lock();
}
// Resume the work. NB: MUST be balanced by a pause.
public void resume() {
// Release the lock.
pause.readLock().unlock();
}
// Stop.
public void cancel() {
// Stop everything.
cancelled = true;
}
// start - like a thread.
public void start() {
// Wrap it in a thread.
new Thread(this).start();
}
// Get the exceptuion that was thrown to stop the thread or null if the thread was cancelled.
public Exception getThrown() {
return thrown;
}
// Create this method to do stuff.
// Calls to this method will stop when pause is called.
// Any thrown exception stops the whole process.
public abstract void step() throws Exception;
// Factory to wrap a Stepper in a PauseableThread
public static PauseableThread make(Stepper stepper) {
StepperThread pauseableStepper = new StepperThread(stepper);
// That's the thread they can pause/resume.
return pauseableStepper;
}
// One of these must be used.
public interface Stepper {
// A Stepper has a step method.
// Any exception thrown causes the enclosing thread to stop.
public void step() throws Exception;
}
// Holder for a Stepper.
private static class StepperThread extends PauseableThread {
private final Stepper stepper;
StepperThread(Stepper stepper) {
this.stepper = stepper;
}
@Override
public void step() throws Exception {
stepper.step();
}
}
// My test counter.
static int n = 0;
// Test/demo.
public static void main(String[] args) throws InterruptedException {
try {
// Simple stepper that just increments n.
Stepper s = new Stepper() {
@Override
public void step() throws Exception {
n += 1;
Thread.sleep(10);
}
};
PauseableThread t = PauseableThread.make(s);
// Start it up.
t.start();
Thread.sleep(1000);
t.pause();
System.out.println("Paused: " + n);
Thread.sleep(1000);
System.out.println("Resuminng: " + n);
t.resume();
Thread.sleep(1000);
t.cancel();
} catch (Exception e) {
}
}
}
编辑:修改代码以使其更常用。
答案 1 :(得分:1)
您最好的选择是使用wait()/ notify()或只是切换到ScheduledExecutorService
正确的wait()/ notify()使用可能很棘手。我强烈推荐“Java Concurrency in Practice”来了解有关线程的更多信息。
答案 2 :(得分:0)
我认为这里最好的方法是使用Thread.wait
作为等待线程而不是休眠,并在你正在等待的线程中使用Thread.notify
。
更多信息:
http://www.javamex.com/tutorials/synchronization_wait_notify.shtml
答案 3 :(得分:0)
您可以使用显示器而不是睡眠线来提高效率。您只需使用关键字synchronized在代码中创建块。最后一个对象就是监视器。在监视器上的API中查看更多内容。