进程是程序的一次执行过程,是系统运行程序的基本单位,所以进程是动态的。系统运行一个程序便是一个进程从建立、运行到消亡的过程。java
线程是比进程更小的执行单位,一个进程在其执行的过程当中能够产生多个线程。线程共享进程的堆和方法区的资源,同时线程还有私有的程序计数器、虚拟机栈和本地方法栈资源。安全
并行:单位时间内,多个任务同时执行。多线程
并发:同一时间段,多个任务都在执行(单位时间内不必定同时执行)。并发
状态名称 | 说明 |
---|---|
NEW | 初始状态,线程被构建 |
RUNNABLE | 运行状态,包括运行中和就绪两种状态 |
BLOCKED | 阻塞状态,表示线程阻塞于锁 |
WAITING | 等待状态,表示线程进入等待状态,若是其余线程不通知则不会唤醒 |
TIMED_WAITING | 超时等待状态,通过指定等待时间后会自动唤醒 |
TERMINATED | 终止状态,表示线程已经执行完毕 |
经过继承Thread类并重写run() 方法能够建立线程,调用start()方法来启动线程。ide
public class ThreadDemo01 { public static void main(String[] args) { MyThread01 t = new MyThread01(); t.start(); // 线程名称:Thread-0 } } /** * 继承Thread类 */ class MyThread01 extends Thread { @Override public void run() { System.out.println("线程名称:" + Thread.currentThread().getName()); } }
因为Java中类的单继承特性,当一个类继承Thread类后就不能继承其它的类了。线程
经过实现Runnable接口并重写run() 方法能够建立一个线程,同时能够继承其它的类。code
public class ThreadDemo02 { public static void main(String[] args) { new Thread(new MyThread02()).start(); // 线程名称:Thread-0 } } /** * 实现Runnable接口 */ class MyThread02 extends Object implements Runnable { @Override public void run() { System.out.println("线程名称:" + Thread.currentThread().getName()); } }
采用这种方式建立线程时能够利用JDK1.8的新特性lambda表达式,无需实现Runnable接口的实现类,简化代码。blog
public class ThreadDemo02 { public static void main(String[] args) { new Thread(() -> System.out.println(Thread.currentThread().getName())).start(); } }
有返回值的任务必须实现Callable接口并从新call() 方法,返回值封装在future中,经过get()方法获取返回的Object,再结合线程池接口ExecutorService实现有返回值得线程运行。继承
import java.util.concurrent.*; public class ThreadDemo03 { public static void main(String[] args) { // 建立单个线程的线程池 ExecutorService es = Executors.newSingleThreadExecutor(); // 提交任务到线程池并获取执行结果 Future<Integer> future = es.submit(new MyThread03()); // 关闭线程池 es.shutdown(); try { if (future.get() != null) { System.out.println("Callable子线程计算结果:" + future.get()); } else { System.out.println("Callable子线程未获取到结果"); } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } /** * 实现Callable接口 */ class MyThread03 implements Callable<Integer> { private int sum; @Override public Integer call() throws Exception { System.out.println("Callable子线程开始计算..."); Thread.sleep(1000); for (int i = 0; i < 10; i++) { sum += i; } System.out.println("Callable子线程计算结束..."); return sum; } }
运行结果:接口
正常运行结束:程序运行结束,线程自动结束;
使用退出标志退出线程:设置一个boolean类型的标志,经过设置标志的值终止线程;
public class ThreadTerminatedDemo01 extends Thread{ public volatile boolean exit = false; @Override public void run() { while (!exit) { System.out.println(Thread.currentThread().getName()); } } }
interrupt() 方法中断线程
public class ThreadTerminatedDemo02 extends Thread{ @Override public void run() { // 非阻塞状态下经过判断中断标志来退出 while (!isInterrupted()) { try { // 阻塞状态下捕获中断异常来退出 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); // 捕获到异常后执行break跳出循环 break; } } } }
stop() 方法终止线程(线程不安全)
程序中直接使用Thread.stop()
方法能够强行终止线程,但会有线程不安全问题。当调用Thread.stop()
方法后,线程抛出ThreadDeathError异常,而且会释放其持有的全部锁,从而可能致使数据出现不一致的状况。
线程之间因为相互竞争资源或调度不当而同时被阻塞,它们中的一个或所有都在等待某个资源被释放。
public class ThreadDeadLockDemo { private static Object r1 = new Object(); private static Object r2 = new Object(); public static void main(String[] args) { // Thread01 new Thread(() -> { synchronized (r1) { try { System.out.println(Thread.currentThread().getName() + " has got r1."); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is waiting for r2."); synchronized (r2) { System.out.println(Thread.currentThread().getName() + " has got r2."); } } }, "Thread01").start(); // Thread02 new Thread(() -> { synchronized (r2) { System.out.println(Thread.currentThread().getName() + " has got r2."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is waiting for r1."); synchronized (r1) { System.out.println(Thread.currentThread().getName() + " has got r1."); } } }, "Thread02").start(); } }
执行结果:
互斥:该资源任意一个时刻智能由一个线程占用;
请求保持:一个进程因请求资源而阻塞时不会释放已经得到的资源;
不可剥夺:一个线程已经得到的资源不能被其它线程强行剥夺,只有等使用结束才会被释放;
循环等待:若干进程之间造成一种头尾相接的循环等待资源关系。
破坏产生死锁的四个必要条件中的一个。
破坏互斥条件:没法破坏。
破坏请求保持条件:线程一次性申请全部的资源。
破坏不可剥夺条件:占用部分资源的线程进一步申请资源时,若是申请不到能够主动释放已占有的资源。
破坏循环等待条件:靠按序申请预防。按某一顺序申请资源,释放资源则反序释放,破坏循环等待条件。
public class BreakDeadLockDemo { private static Object r1 = new Object(); private static Object r2 = new Object(); public static void main(String[] args) { // Thread01 new Thread(() -> { synchronized (r1) { try { System.out.println(Thread.currentThread().getName() + " has got r1."); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is waiting for r2."); synchronized (r2) { System.out.println(Thread.currentThread().getName() + " has got r2."); } } }, "Thread01").start(); // Thread02 new Thread(() -> { synchronized (r1) { System.out.println(Thread.currentThread().getName() + " has got r1."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is waiting for r1."); synchronized (r2) { System.out.println(Thread.currentThread().getName() + " has got r2."); } } }, "Thread02").start(); } }
对Thread02线程进行修改后,破坏循环等待条件,从而避免死锁。执行结果以下:
建立一个线程时须要重写run()方法,调用start()方法后会启动该线程。调用start()方法会执行线程的相应准备工做而后自动执行run()方法的内容,这是真正的多线程工做。执行run()方法会把run()方法当成main线程下的普通方法去执行,并不会再某个线程中执行,不是多线程的工做。
调用start()方法能够启动线程并使该线程进入就绪状态,而执行run()方法只是线程中的一个普通方法调用,仍在main线程里执行。