创建线程

继承Thread

  1. @Override
  2. public void run() {
  3. System.out.println("MyThread");
  4. }
  5. public static void main(String[] args) {
  6. ThreadDemo threadDemo = new ThreadDemo();
  7. threadDemo.start();
  8. }

再调用start() 方法之后,该线程才能启动,虚拟机会会先为我们创建一个线程,等到这个线程第一次获取到时间片再调用run()方法。
不能重复调用start()方法,重复调用会抛出 IllegalThreadStateException 异常

  1. public synchronized void start() {
  2. /**
  3. * This method is not invoked for the main method thread or "system"
  4. * group threads created/set up by the VM. Any new functionality added
  5. * to this method in the future may have to also be added to the VM.
  6. *
  7. * A zero status value corresponds to state "NEW".
  8. */
  9. if (threadStatus != 0)
  10. throw new IllegalThreadStateException();
  11. }

实现Runnable() 接口

  1. @FunctionalInterface
  2. public interface Runnable {
  3. public abstract void run();
  4. }

可以看到Runnable 是一个函数式接口,这意味着我们可以使用Java 8 的函数式编程来简化代码

  1. public static void main(String[] args) {
  2. new Thread(() -> System.out.println("hello world")).start();
  3. }

通常来说,我们使用Runnable 和Thread 来创建一个新的线程,但他们都有一个弊端,就是run()没有返回值, 有时候我们希望开启一个线程去执行一个任务,并且执行任务后有一个返回值。

Callable 接口

  1. @FunctionalInterface
  2. public interface Callable<V> {
  3. V call() throws Exception;
  4. }

Callable 一般配合线程池工具 ExecutorService来使用。

  1. public static void main(String[] args) throws ExecutionException, InterruptedException {
  2. ExecutorService executorService = Executors.newCachedThreadPool();
  3. Future<Integer> future = executorService.submit(() -> 2);
  4. //注意调用get()方法会阻塞当前线程,直到得到结果
  5. System.out.println(future.get());
  6. }

Future 接口

  1. public interface Future<V> {
  2. /**
  3. * Attempts to cancel execution of this task. This attempt will
  4. * fail if the task has already completed, has already been cancelled,
  5. * or could not be cancelled for some other reason. If successful,
  6. * and this task has not started when {@code cancel} is called,
  7. * this task should never run. If the task has already started,
  8. * then the {@code mayInterruptIfRunning} parameter determines
  9. * whether the thread executing this task should be interrupted in
  10. * an attempt to stop the task.
  11. *
  12. * <p>After this method returns, subsequent calls to {@link #isDone} will
  13. * always return {@code true}. Subsequent calls to {@link #isCancelled}
  14. * will always return {@code true} if this method returned {@code true}.
  15. *
  16. * @param mayInterruptIfRunning {@code true} if the thread executing this
  17. * task should be interrupted; otherwise, in-progress tasks are allowed
  18. * to complete
  19. * @return {@code false} if the task could not be cancelled,
  20. * typically because it has already completed normally;
  21. * {@code true} otherwise
  22. */
  23. boolean cancel(boolean mayInterruptIfRunning);
  24. /**
  25. * Returns {@code true} if this task was cancelled before it completed
  26. * normally.
  27. *
  28. * @return {@code true} if this task was cancelled before it completed
  29. */
  30. boolean isCancelled();
  31. /**
  32. * Returns {@code true} if this task completed.
  33. *
  34. * Completion may be due to normal termination, an exception, or
  35. * cancellation -- in all of these cases, this method will return
  36. * {@code true}.
  37. *
  38. * @return {@code true} if this task completed
  39. */
  40. boolean isDone();
  41. /**
  42. * Waits if necessary for the computation to complete, and then
  43. * retrieves its result.
  44. *
  45. * @return the computed result
  46. * @throws CancellationException if the computation was cancelled
  47. * @throws ExecutionException if the computation threw an
  48. * exception
  49. * @throws InterruptedException if the current thread was interrupted
  50. * while waiting
  51. */
  52. V get() throws InterruptedException, ExecutionException;
  53. /**
  54. * Waits if necessary for at most the given time for the computation
  55. * to complete, and then retrieves its result, if available.
  56. *
  57. * @param timeout the maximum time to wait
  58. * @param unit the time unit of the timeout argument
  59. * @return the computed result
  60. * @throws CancellationException if the computation was cancelled
  61. * @throws ExecutionException if the computation threw an
  62. * exception
  63. * @throws InterruptedException if the current thread was interrupted
  64. * while waiting
  65. * @throws TimeoutException if the wait timed out
  66. */
  67. V get(long timeout, TimeUnit unit)
  68. throws InterruptedException, ExecutionException, TimeoutException;
  69. }

cancel()方法是试图取消一个线程的执行,是试图取消,并不一定取得成功

线程组(ThreadGroup)

Java中用ThreadGroup来表示线程组,我们可以使用线程组对线程进行批量控制。
每一个线程必然存在于一个ThreadGroup 中,Thread 不能独立于ThreadGroup 存在,如果没有显式指定,那么默认将父线程设置为自己的线程组。
public static void main(String[] args) { // ThreadGroup 是main new Thread(() -> System.out.println(Thread.currentThread().getThreadGroup().getName())).start(); System.out.println(ThreadDemo.currentThread().getName()); }
ThreadGroup 是一个标准的向下引用的数状结构,这样子设计的原因是防止”上级”线程被下级线程引用而无法有效地被GC 回收。

线程的优先级

Java 的线程的优先级可以指定,范围是1~10 .默认优先级为 5,。但是不是所有的操作系统都支持10级优先级,Java只是给操作系统一个参考值,线程最终在操作系统的优先级是多少还是有操作系统来决定的。
优先级更高的线程有更好的机率得到执行。
如果某个线程的优先级大于线程所在组的最大优先级,那个该线程的优先级将会失效,取而代之的是线程组的最大优先级。

守护线程

守护线程的默认优先级比较低,如果所有的非守护线程都结束了,这个守护线程也会自动结束。

线程常用方法

sleep()

yield()

放弃当前的CPU 执行的时间片,让其他线程执行

interrupt()

仅仅作为子线程的中断标志,子线程并没有真正中断,配合 isInterrupted() 方法一起使用

state()

  1. public static void main(String[] args) throws InterruptedException {
  2. Thread thread = new Thread(() -> {
  3. if (Thread.interrupted()) {
  4. return;
  5. }
  6. System.out.println("00000");
  7. });
  8. thread.start();
  9. thread.interrupt();
  10. Thread.sleep(3000);
  11. System.out.println(thread.getState());
  12. }