1、优先级
每个Java线程都有对应的优先级,高优先级的线程比低优先级的线程有更多的执行机会。新创建的Java线程默认的优先级是5, 最低是1,最高是10;
/*** The minimum priority that a thread can have.*/public final static int MIN_PRIORITY = 1;/*** The default priority that is assigned to a thread.*/public final static int NORM_PRIORITY = 5;/*** The maximum priority that a thread can have.*/public final static int MAX_PRIORITY = 10;
Note:如果在一个线程中创建一个新的线程,新线程的默认优先级和所在线程的优先级保持一致。
2、daemon 或 非daemon
一个Java线程可以是daemon的也可以是非daemon的,JVM在启动的时候启动了main线程,该线程是非daemon;JVM在下面2的情况下会退回:
- 调用
Runtime.exit()方法 -
3、创建线程的方式
有2种创建线程的方式,一种是继承
Thread类;一种是直接new一个Thread对象,并在构造函数中传入一个Runnable对象。继承
```java class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
} } PrimeThread p = new PrimeThread(143); p.start();
//new class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; }
public void run() {// compute primes larger than minPrime . . .}
} PrimeRun p = new PrimeRun(143); new Thread(p).start();
<a name="b3jl1"></a>### 4、线程的状态JDK中关于线程状态的定义:- `new `: 一个新创建的,没有调用`start`方法的线程处于该状态;- `RUNNABLE `:可执行的,在JVM中是处于执行中,但是在等待其它的操作系统资源,如cpu资源;- `BLOCKED `:阻塞的,一个线程在进入(或再次进入)一个同步方法或同步块时等待监视器锁时处于该状态。- `WAITING `:等待,一个线程在调用了如下的方法时会处于等待状态:<br />1.`Object.wait`<br />2.`Thread.join` //正在主线程中调用一个一个线程的`join`方法,在主线程处于等待状态<br />3.`LockSupport#park()`- `TIMED_WAITING` 等待的,不过该等待状态是有时间限制的。一个线程调用下面的方法会进入该状态:<br />1.`Thread.sleep`<br />2.`Object.wait`<br />3.`Thread.join`<br />4.`LockSupport.parkNanos`<br />5.`LockSupport.parkUntil`- `TERMINATED` 终止,当一个线程执行完成后处于该状态<a name="x9Raa"></a>### 5、线程的调度理想的情况下,每个程序的线程都拥有一个专属于自己的处理器;在计算机还不能拥有几千,甚至几百万CPU处理器的情况下,多个线下需要共享仅有的cpu资源,如果分配线程执行所需的cpu资源就需要线程调度器的调度了。在操作系统层面有自己的线程调度器,在JVM中也存在Java线程调度器。<br />在Java线程调度中有2点比较重要:1. Java规范并没有强制要求每个JVM按照特定的调度规则调用线程,或者必须包含一个线程调度器。线程调度的实现完全是依赖平台的。1. 在编写Java多线程代码时,唯一需要考虑的是不要让一个线程大量的占用cpu时间(eg.死循环)。大多数平台上JVM的线程调度是依赖操作系统本身的线程调度器的,每个线下有不同的优先级,在基于时间片的规则下,高优先级的线程拥有更多的CPU执行机会;相同优先级的线程可以按照FIFO调度。<a name="MeNg7"></a>### 6、`Runnable`、`Callable`、`Future` 和 `FutureTasek`的区别Java中存在`Runnable`、`Callable`、`Future`、`FutureTask`这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,通过下面的简单示例来了解一下它们的作用与区别。<a name="CwkIr"></a>#### 6.1 `Runnable``Runnable` 应该是这几个类使用的最多的一个。JDK的文档说明:如果一个类的实例想要通过一个线程来执行,则该类应该实现`Runnable`接口。`Runnable`被设计用来对那些处于`active`状态时会执行代码的对象提供一个统一的协议。例如`Thread`类就实现了`Runnable`接口。```javapublic interface Runnable {public abstract void run();}
6.2 Callable
Callable 表示一个可以携带返回结果的任务。该接口的实现类需要一个没有参数的call方法。Callable 和 Runnable类似,都是被设计用来被另外一个线程执行的任务。但是Runnable不能返回一个结果,且不能抛出一个checked异常。
public interface Callable<V> {/*** Computes a result, or throws an exception if unable to do so.** @return computed result* @throws Exception if unable to compute a result*/V call() throws Exception;}
6.3 Future
一个Futrue表示一个异步计算的结果。它提供了一系列方法,用来检测计算是否完成,获取计算结果,等待计算结果等。只能通过get方法获取计算结果;如果计算没有完成,在必要条件下,则get方法一直等待,直到任务完成。cancel方法用来取消任务。其它的方法都是用来测试计算是否完成,或是否取消。一旦计算完成后,就不可以被取消。如果想使用Future,但并不需要返回一个结果,则可以使用Future<?>并返回null。
一个简单的例子(JDK原文):
class App {ExecutorService executor = ...ArchiveSearcher searcher = ...void showSearch(final String target) throws InterruptedException {Future<String> future = executor.submit(new Callable<String>() {public String call() {return searcher.search(target);}});displayOtherThings();try{displayText(future.get()); // use future}catch(ExecutionException ex){cleanup(); return;}}}
6.4 FutureTask
FutureTask 表示一个可以取消的异步计算任务。它实现了Runnable接口和Future接口。FutureTask 可以用来包装Runnable和Callable对象。应该FutureTask实现了Runnable接口。同时可以通过被提交到Executor去执行。
public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW; // ensure visibility of callable}public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW; // ensure visibility of callable}
可以看到,Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下 :
public static <T> Callable<T> callable(Runnable task, T result) {if (task == null)throw new NullPointerException();return new RunnableAdapter<T>(task, result);}
RunnableAdapter适配器
/*** A callable that runs given task and returns given result*/static final class RunnableAdapter<T> implements Callable<T> {final Runnable task;final T result;RunnableAdapter(Runnable task, T result) {this.task = task;this.result = result;}public T call() {task.run();return result;}}
7、总结
由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。
并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。因此FutureTask既是Future、Runnable,又是包装了Callable(如果是Runnable最终也会被转换为Callable), 它是这两者的合体。
