线程
线程与过程
过程是操作系统分配资源的最小单位,而线程是程序执行的最小单位,他们都是能够并发执行的。一个过程至多有一个线程,这些线程共享过程的资源空间。
线程简介
每个线程都有一个优先级,高优先级的线程比低优先级的线程先执行。优先级的取值范畴是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时,线程将从有限期待状态进入阻塞状态。
阻塞状态到运行状态
线程处于阻塞状态,如果获取到锁对象,就进入运行状态。
发表回复