进程是程序的一次执行过程,是系统运行程序的基本单位,所以进程是动态的。系统运行一个程序便是一个进程从建立,运行到消亡的过程。java
在 Java 中,当咱们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。缓存
线程与进程类似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程当中能够产生多个线程。与进程不一样的是同类的多个线程共享进程的堆和方法区资源,但每一个线程有本身的程序计数器、虚拟机栈和本地方法栈,因此系统在产生一个线程,或是在各个线程之间做切换工做时,负担要比进程小得多,也正由于如此,线程也被称为轻量级进程。多线程
一个进程中能够有多个线程,多个线程共享进程的堆和方法区 (JDK1.8 以后的元空间)资源,可是每一个线程有本身的程序计数器、虚拟机栈 和 本地方法栈。并发
总结: 线程 是 进程 划分红的更小的运行单位。线程和进程最大的不一样在于基本上各进程是独立的,而各线程则不必定,由于同一进程中的线程极有可能会相互影响。线程执行开销小,但不利于资源的管理和保护;而进程正相反函数
多个线程同时被阻塞,它们中的一个或者所有都在等待某个资源被释放。因为线程被无限期地阻塞,所以程序不可能正常终止。工具
public class DeadLockDemo { private static Object resource1 = new Object();//资源 1 private static Object resource2 = new Object();//资源 2 public static void main(String[] args) { new Thread(() -> { synchronized (resource1) { System.out.println(Thread.currentThread() + "get resource1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread() + "waiting get resource2"); synchronized (resource2) { System.out.println(Thread.currentThread() + "get resource2"); } } }, "线程 1").start(); new Thread(() -> { synchronized (resource2) { System.out.println(Thread.currentThread() + "get resource2"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread() + "waiting get resource1"); synchronized (resource1) { System.out.println(Thread.currentThread() + "get resource1"); } } }, "线程 2").start(); } }
咱们只要破坏产生死锁的四个条件中的其中一个就能够了。线程
调用 start 方法方可启动线程并使线程进入就绪状态,而 run 方法只是 thread 的一个普通方法调用,仍是在主线程里执行。code
总结: synchronized 关键字加到 static 静态方法和 synchronized(class)代码块上都是是给 Class 类上锁。synchronized 关键字加到实例方法上是给对象实例上锁。尽可能不要使用 synchronized(String a) 由于JVM中,字符串常量池具备缓存功能!对象
线程池提供了一种限制和管理资源(包括执行一个任务)。 每一个线程池还维护一些基本统计信息,例如已完成任务的数量。blog
使用线程池的好处:
若是想让线程池执行任务的话须要实现的Runnable接口或Callable接口。 Runnable接口或Callable接口实现类均可以被ThreadPoolExecutor或 ScheduledThreadPoolExecutor执行。二者的区别在于 Runnable 接口不会返回结果可是 Callable 接口能够返回结果。
备注: 工具类Executors能够实现Runnable对象和Callable对象之间的相互转换。(Executors.callable(Runnable task)或Executors.callable(Runnable task,Object resule))。
execute() 方法用于提交不须要返回值的任务,因此没法判断任务是否被线程池执行成功与否;
submit() 方法用于提交须要返回值的任务。线程池会返回一个Future类型的对象,经过这个Future对象能够判断任务是否执行成功,而且能够经过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后当即返回,这时候有可能任务没有执行完。
生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞。
生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区做为仓库,生产者能够将产品放入仓库,消费者则能够从仓库中取走产品。在Java中一共有四种方法支持同步,其中前三个是同步方法,一个是管道方法。