IllegalThreadStateException的原因解析
mThread = new MThread();
mThread.start();
mThread.interrupt();
mThread.start();
这段代码运行,就会出现上面的异常,从字面是理解也很容易理解:非法线程状态异常,线程已经start。
具体原因也很容易找到,看一下thread.start()里面做了什么:
public synchronized void start() {
checkNotStarted();
hasBeenStarted = true;
nativeCreate(this, stackSize, daemon);
}
private void checkNotStarted() {
if (hasBeenStarted) {
throw new IllegalThreadStateException("Thread already started");
}
}
在线程开始的时候会将hasBeenStarted设置成true,而在interrupt终止线程的时候,并没有将hasBeenStarted设置成false,所以在第二次start线程的时候会出现IllegalThreadStateException。
解决方法
- new 一个新的thread
- thread不终止
对于第一个方法,创建新的线程去执行,这个方法不建议使用,因为大量的线程会影响你应用的性能,而第二个方法不终止线程,听起来可行,但是有一些具体情况,必须需要我们终止我们的线程,有没有一种情况是在一个线程里面我们想什么时候让它运行就什么时候运行,不运行的时候等待。答案是有的——PriorityBlockingQueue。
BlockingQueue | 抛出异常 | 特殊值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | pull() | take() | pull(time,unit) |
检查 | element() | peek() | 不可用 | 不可用 |
- add(E e):把e加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则招聘异常。
- offer(E e):表示如果可能的话,将e加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false。
- put(E e):把e加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续。
- take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止
其中take方法取值失败后:阻断进入等待状态直到Blocking有新的对象被加入为止。
private final PriorityBlockingQueue<Long> mQueue =
new PriorityBlockingQueue<>();
mQueue.add(delayTime);
private class Dispatcher extends Thread {
WeakReference<MainActivity> context;
public Dispatcher(MainActivity activity) {
context = new WeakReference<>(
activity);
}
@Override
public void run() {
super.run();
long loadTime;
while (true) {
try {
loadTime = mQueue.take();
} catch (Exception e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
if (context == null || context.get() == null) {
return;
}
continue;
}
if (context == null || context.get() == null) {
return;
}
if (isStop.get()) {
return;
}
int i = mProgressBar == null ? 0 : mProgressBar.getProgress();
for (; i < 100; ) {
if (isStop.get()) {
return;
}
if (context == null || context.get() == null) {
return;
}
i += ratio;
}
}
}
}
mQueue.take()取值失败后会阻塞,当我们需要线程开始运行的时候,只要向队列里面add值就可以了