共计 5685 个字符,预计需要花费 15 分钟才能阅读完成。
线程
线程与过程
过程是操作系统分配资源的最小单位,而线程是程序执行的最小单位,他们都是能够并发执行的。一个过程至多有一个线程,这些线程共享过程的资源空间。
线程简介
每个线程都有一个优先级,高优先级的线程比低优先级的线程先执行。优先级的取值范畴是 1 到 10 的整数,默认是 5。每个线程有可能被标记为一个守护线程。当一个线程创立另外一个新的线程对象,新的线程的优先级等于创立他的线程的优先级;如果新的线程对象是一个守护线程当且仅当创立他的线程是一个守护线程。
线程分类
Java 线程分为 守护线程 (Daemon Thread) 和用户线程(User Thread)。守护线程和用户线程基本上是一样的,惟一的区别是如果用户线程全副退出运行了,不论有没有守护线程虚拟机都会退出。守护线程的作用是为其余的线程的运行提供服务,最典型的守护线程就是 GC(垃圾回收期)。
创立线程
创立线程的形式
创立一个线程类有三种形式:
- 继承 Thread 类
- 实现 Runnable 接口
- 实现 Callable 接口
Thread
Thread 简介
Thread 是创立线程最要害的一个类,这个词自身也代表线程,Thread 类实现了 Runnable 接口。
代码示例
public class ThreadDemo extends Thread {public void run() {for (int i = 0; i < 60; i++) {System.out.println(getName() + ":" + i);
}
}
}
public class Demo{public static void main(String[] args) {ThreadDemo t1 = new ThreadDemo();
ThreadDemo t2 = new ThreadDemo();
t1.start();
t2.start();}
}
Runnable
Runnable 简介
Runnable 是提供线程的接口,有一个形象办法 public abstract void run()
。实现了这个接口的类必须实现它的run
办法。
代码示例
public class Runnable implements Runnable{public void run() {public void run() {for (int i = 0; i < 60; i++) {System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
public class Demo{public static void main(String[] args) {RunnableDemo run = new RunnableDemo();
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
t1.start();
t2.start();}
}
Callable 和 Future
Callable 和 Future 简介
Thread 和 Runnable 创立线程不能获取线程的返回值。从 Java1.5 开始,就提供了 Callable 和 Future,通过他们能够在工作执行结束之后失去工作执行后果。
- Callable 接口:能够返回一个后果或者抛出一个异样的一个工作,实现者定义一个没有参数的 call 办法。区别于 Thread 和 Runnable 的 run 办法,Calllable 工作执行的办法是 call。
- Future 接口:Future 接口代表了异步计算的后果,提供了一些办法用于查看计算结果是否实现,获取计算结果等。FutureTask 类提供了 Future 接口的实现,并且实现了 Runnable 接口。
代码案例
public class MyCallable implements Callable<Integer> {public Integer call() {
int sum = 0;
for (int i = 0; i <= 100; i++) {sum += i;}
return new Integer(sum);
}
}
public class Demo{public static void main(String[] args) {MyCallable callable = new MyCallable();
FutureTask<Integer> result = new FutureTask<Integer>(callable);
new Thread(result).start();
try {Integer value = result.get();
} catch (InterruptedException e) {e.printStackTrace();
} catch (ExecutionException e) {e.printStackTrace();
}
}
}
线程生命周期
线程状态
在 Thread 类中有一个外部枚举类 State 代表了线程的状态,一个线程从创立到销毁就是一个残缺的生命周期。
public enum State {
/**
* 线程被创立,还没有开始运行
*/
NEW,
/**
* 线程运行状态,运行状态的线程是正在被 Java 虚拟机执行,然而也可能正在期待操作系统的其余资源例如处理器
*/
RUNNABLE,
/**
* 线程阻塞状态,期待监视器锁。处于阻塞状态线程是在期待监视器锁为了:进入同步代码块 / 办法或者被调用后重 * 新进入同步代码 / 办法
*/
BLOCKED,
/**
* 线程期待状态,一个线程处于期待状态因为调用了以下这几种办法:Object.wait;Thread.join;LockSupp
* ort.park。处于期待的线程正在期待另一个线程执行一个特定的操作。*/
WAITING,
/**
* 线程超时期待状态,一个线程处于超时期待状态在一个特定的等待时间,因为调用了以下几个办法 Thread.slee
* p;Object.wait(long);Thread.join(long);LockSupport.parkNanos;LockSupport.parkUntil。*/
TIMED_WAITING,
/**
* 线程完结状态,线程曾经执行实现了。*/
TERMINATED;
}
线程状态转换
线程状态转换图
线程从创立后就在几个状态中切换。上面是一个线程状态转换图,调用不同的办法就能够切换线程线程的状态。
运行状态 & 有限期待
调用 Object.wait();Thread.join();LockSupport.park()办法能够让线程从运行状态进入到有限期待状态。
-
wait 办法
是属于 Object 类的,对象调用 wait 办法后会让以后持有对象锁的线程开释以后对象锁并进入期待队列。对象调用 notify 从期待队列随机抉择一个线程唤醒去竞争对象锁,对象调用 notifyall 会唤醒期待队列中的所有线程去竞争对象锁。public class Demo {public static void main(String[] args) {Demo demo = new Demo(); Thread t1 = new Thread(() -> {synchronized (demo) {System.out.println("t1 start"); try {demo.wait(); } catch (InterruptedException e) {e.printStackTrace(); } System.out.println("t1 end"); } }); Thread t2 = new Thread(() -> {synchronized (demo) {System.out.println("t2 start"); System.out.println("t2 end"); demo.notify();} }); t1.start(); t2.start();} }
-
join 办法
是属于 Thread 类的,join 办法是阻塞调用此办法的线程,当线程 a 调用线程 b 的 b.join(long),线程 a 会阻塞直到线程 b 执行实现。public class Demo {public static void main(String[] args) throws Exception {System.out.println("main start"); Thread t1 = new Thread(() -> {System.out.println("t1 start"); System.out.println("t1 end"); }); t1.start(); t1.join(); System.out.println("main end"); } }
-
park 办法
是属于 LockSupport 类的,LockSupport 是一个线程阻塞工具类,所有的办法都是静态方法,能够应用 park 办法来阻塞线程,应用 unpart 来唤醒线程。public class Demo {public static void main(String[] args) {System.out.println("main start"); Thread t1 = new Thread(() -> {System.out.println("t1 start"); LockSupport.park(); System.out.println("t1 end"); }); t1.start(); LockSupport.unpark(t1); System.out.println("main end"); } }
运行状态 & 超时期待
调用 Object.wait(long);Thread.join(long);LockSupport.park(long)办法能够让线程从运行状态进入到期待状态,直到达到等待时间或者被动唤醒。
-
wait(long)办法
是属于 Object 类的,当对象调用 wait(long)后会让以后持有对象锁的线程开释掉以后对象锁进入期待队列,直到达到等待时间或者对象调用 notify 或者 notifyall 从期待队列中唤醒线程,线程又从新开始竞争锁。public class Demo {public static void main(String[] args) {Demo demo = new Demo(); Thread t1 = new Thread(() -> {synchronized (demo) {for (int i = 0; i < 1000; i++) {if (i == 500) { try {demo.wait(100); } catch (InterruptedException e) {e.printStackTrace(); } } System.out.println("------t1------:" + i); } } }); Thread t2 = new Thread(() -> {synchronized (demo) {for (int i = 0; i < 1000; i++) {System.out.println("------t2------:" + i); } } }); t1.start(); t2.start();} }
-
join(long)办法
是属于 Thread 类的,join(long)办法是阻塞调用此办法的线程,当线程 a 调用线程 b 的 b.join(long),线程 a 会阻塞直到达到阻塞工夫或者线程 b 执行实现。public class Demo {public static void main(String[] args) throws Exception {System.out.println("main start"); Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {System.out.println("----t1----:" + i); } }); t1.start(); t1.join(1); System.out.println("main end"); } }
-
parkUntil(long)和 parkNanos(long)
是属于 LockSupport 类的,LockSupport 是一个线程阻塞工具类,所有的办法都是静态方法,能够应用 parkUntil(long)和 parkNanos(long)办法来阻塞线程。parkNanons 是阻塞 long 工夫,parkUntil 是阻塞截止到 long 工夫。public class Demo {public static void main(String[] args) {System.out.println("main start"); Thread t1 = new Thread(() -> {System.out.println("t1 start"); LockSupport.parkNanos(3000000000L); System.out.println("t1 end"); }); t1.start(); System.out.println("main end"); } }
public class Demo {public static void main(String[] args) throws Exception{System.out.println("main start"); Thread t1 = new Thread(() -> {System.out.println("t1 start"); String dateTimeStr = "2021-04-04 14:57:00"; DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr, df); LockSupport.parkUntil(dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli()); System.out.println("t1 end"); }); t1.start(); System.out.println("main end"); } }
有限期待 & 阻塞状态
对象调用 wait 办法后线程会进入有限期待状态,当对象调用 notify 或者 notifyAll 时,线程将从有限期待状态进入阻塞状态。
阻塞状态到运行状态
线程处于阻塞状态,如果获取到锁对象,就进入运行状态。