作java web开发,一直以来比较依赖java框架和oracle数据库的功能。由于通常遇到高并发的状况并很少,企业内软件多半用户数很少,即便偶尔遇到,也都在oracle数据库中处理了。 java
对java的多线程开发,一直以来只有一个简单的概念,没有深刻使用理解过,但愿此次利用网上的内容,可以回顾一下。 web
进程:一个内存中运行的应用程序,每一个进程都有本身独立的一块内存空间,一个进程中能够启动多个线程。好比在Windows系统中,一个运行的exe就是一个进程。 数据库
线程:进程中的一个执行流程,一个进程中能够运行多个线程。好比java.exe进程中能够运行不少线程。线程老是属于某个进程,进程中的多个线程共享进程的内存。 编程
操做系统中的进程是资源的组织单位。进程有一个包含了程序内容和数据的地址空间,以及其它的资源,包括打开的文件、子进程和信号处理器等。不一样进程的地址空间是互相隔离的。而线程表示的是程序的执行流程,是CPU调度的基本单位。线程有本身的程序计数器、寄存器、栈和帧等。引入线程的动机在于操做系统中阻塞式I/O的存在。当一个线程所执行的I/O被阻塞的时候,同一进程中的其它线程可使用CPU来进行计算。这样的话,就提升了应用的执行效率。线程的概念在主流的操做系统和编程语言中都获得了支持。 多线程
线程与进程的区别: 并发
地址空间: 进程内的一个执行单元;进程至少有一个线程,它们共享进程的地址空间;而进程有本身独立的地址空间; oracle
资源拥有: 进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源 框架
线程是处理器调度的基本单位,但进程不是. 编程语言
两者都可并发执行. ide
线程共有下面4种状态:
新建状态(New):新建立了一个线程对象,当你用new建立一个线程时,该线程还没有运行。
就绪状态(Runnable):线程对象建立后,其余线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
阻塞状态(Blocked):阻塞状态是线程由于某种缘由放弃CPU使用权,暂时中止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的状况分三种:
等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM把该线程放入锁。
其余阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程从新转入就绪状态。
死亡状态(Dead):
因为run方法的正常退出而天然死亡;
没有捕获到的异常事件终止了run方法的执行,从而致使线程忽然死亡
状态之间的转换能够用下面的两张图来展现
继承Thread类
public class TestThread extends Thread { @Override public void run() { super.run(); for (int i = 0; i < 1000; i++) { System.out.println(“T-“ + i);
try { Thread.sleep(800); } catch (InterruptedException e) { e.printStackTrace(); } } } }
实现Runnable接口
public class TestRunnable implements Runnable {
@Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("R-" + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Thread runnable = new Thread(new TestRunnable()); Thread thread = new TestThread(); thread.start(); runnable.start(); } }
运行结果:
守护线程一般为普通线程提供服务,它们一般有一个无限循环,等待服务请求或执行线程的任务,在没有其余的非守护线程运行时,守护线程将中止工做。即便你不建立任何线程,Java应用程序在默认状况下建立多个线程。他们大可能是守护线程,主要用于处理任务,如垃圾收集或JMX。
守护线程的特色:
优先级很是低
只有当同一个程序的任何其余线程正在运行时执行。
当线程只剩下守护线程的时候,JVM就会退出.可是若是还有其余的任意一个用户线程还在,JVM就不会退出.
用户线程和守护线程二者几乎没有区别,惟一的不一样之处就在于虚拟机的离开:若是用户线程已经所有退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 由于没有了被守护者,守护线程也就没有工做可作了,也就没有继续运行程序的必要了
在JAVA中经过调方法Thread.setDaemon(true)将线程转为守护线程。但须要注意的有:
但必须在调Thread.start()方法以前,由于一旦线程正在运行,你不能修改它的守护进程的状态。
在Daemon线程中产生的新线程也是Daemon的
守护线程应该永远不去访问固有资源,如文件、数据库,由于它会在任什么时候候甚至在一个操做的中间发生中断。
代码示例:
public class DaemonThread { public static void main(String[] args) { Thread thread = new Thread(new ThreadRunnable()); thread.setDaemon(true); thread.start(); try { Thread.sleep(750); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Main Thread ending"); } } class ThreadRunnable implements Runnable { @Override public void run() { int count = 0; while (true) { System.out.println("Hello from Worker " + count++); try { Thread.sleep(350); } catch (InterruptedException e) { e.printStackTrace(); } } } }
运行结果:
Hello from Worker 0 Hello from Worker 1 Hello from Worker 2 Main Thread ending
从运行结果能够看到,随着主线程的结果,原本是无限循环的子线程,也跟着结束了,说明守护线程不会影响程序的结束。
线程的状态转换,主要是由sleep()、wait()、yeid()、join()等几个方法来实现(stop()、interrupt()等方法貌似都有必定的问题,不是很推荐使用)。
sleep方法与wait方法的区别:
sleep方法是静态方法,wait方法是非静态方法。 sleep方法在时间到后会本身“醒来”,但wait不能,必须由其它线程经过notify(All)方法让它“醒来”。 sleep方法一般用在不须要等待资源状况下的阻塞,像等待线程、数据库链接的状况通常用wait。
sleep/wait与yeld方法的区别:
调用sleep或wait方法后,线程即进入block状态,而调用yeld方法后,线程进入runnable状态。
wait与join方法的区别:
wait方法体现了线程之间的互斥关系,而join方法体现了线程之间的同步关系。 wait方法必须由其它线程来解锁,而join方法不须要,只要被等待线程执行完毕,当前线程自动变为就绪。 join方法的一个用途就是让子线程在完成业务逻辑执行以前,主线程一直等待直到全部子线程执行完毕。