线程和进程的关系:
处理多线程就是异步,单线程就是同步
同步是阻塞模式,异步是非阻塞模式
从一定意义上讲,进程就是一个应用程序在处理机上的一次执行过程,它是一个动态的概念,而线程是进程中的一部分,进程包含多个线程在运行
程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,
我们称其为 进程
线程和进程的区别
在于,子进程和父进程有不同的代码和数据空间,而多个线程则
共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文
多线程的好处
多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定。线程的运行中需要
使用计算机的内存资源和CPU
进程间相互独立,同一个进程的各线程间共享。某进程内的线程在其他进程不可见
线程是进程的一个实体,是CPU调度和 分派的基本单位,它是比进程更小的能独立运行的基本表单位。线程自己基本上不可拥有系统资源
什么是进程线程:
进程是指在系统中正在运行的一 个应用程序;程序一旦运行就是进程,或者进程是程序执行时的一个实例
线程是进程的一个实体
进程是资源分配的最小单位
线程是程序执行的最小单位
1.进程拥有独立的堆栈空间和数据段,所以每当启动一个进程时必须分配给他一个独立的地址空间,建立众多的数据表来维护代码段,堆栈段和数据段,系统开销大
线程也拥有自己独立的堆栈空间,但共享代码段,他们彼此之间使用相同的地址空间,共享大部分数据,比进程更节俭,开销小,切换速度也比进程快,效率高。
因为进程是独立的,所有他的安全性比较高,当一个进程崩溃的时候,不会影响其他进程,而线程是进程的一个不同的执行路径。一个线程死掉,就等于一个进程死掉
2.通信机制:
因为进程是相互独立的,互不干扰,所以进程的通信机制相对会复杂,譬如管道,消息,消息队列,共享内存,套接字等通信机制,而线程由于共享字段,所以通信会很方便
3.属于同一进程的所有线程共享该进程的所有资源
4.线程被称为轻量级进程,进程有进程控制块,线程有线程控制块
5、线程只属于一个进程,而一个进程至少有一个线程
选择线程还是进程的取决条件:
1、需要频繁销毁和创建的使用线程,进程的创建和销毁代价太大
2、线程的切换速度比较快,所以需要大量计算或频繁切换时用线程,还有耗时的操作使用线程,可提高程序的响应速度
3、在堆CPU的使用效率上线程更占优势,发展多机分布时用进程,多核分布用线程
4、并行操作使用线程
5、需要更安全时,使用进程,速度更快,使用线程
实现多线程的方法:
一、继承Thread类:
package com.multithread.learning;
/**
*@functon 多线程学习
*@author 林炳文
*@time 2015.3.9
*/
class Thread1 extends Thread{
private String name;
public Thread1(String name) {
this.name=name;
}
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name + "运行 : " + i);
try {
sleep((int) Math.random() * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
Thread1 mTh1=new Thread1("A");
Thread1 mTh2=new Thread1("B");
mTh1.start();
mTh2.start();
}
}
运行结果:
输出:
A运行 : 0
B运行 : 0
A运行 : 1
A运行 : 2
A运行 : 3
A运行 : 4
B运行 : 1
B运行 : 2
B运行 : 3
B运行 : 4
再运行一下:
A运行 : 0
B运行 : 0
B运行 : 1
B运行 : 2
B运行 : 3
B运行 : 4
A运行 : 1
A运行 : 2
A运行 : 3
A运行 : 4
注意start()方法重复调用,会出现java.lang.IllegalThreadStateException
Thread1 mTh1=new Thread1(“A”);
Thread1 mTh2=mTh1;
mTh1.start();
mTh2.start();
输出:
Exception in thread “main” java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
at com.multithread.learning.Main.main(Main.java:31)
A运行 : 0
A运行 : 1
A运行 : 2
A运行 : 3
A运行 : 4
二、实现java.lang.Runnable接口
package com.multithread.runnable;
class Thread2 implements Runnable{
private String name;
public Thread2(String name) {
this.name=name;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name + "运行 : " + i);
try {
Thread.sleep((int) Math.random() * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
new Thread(new Thread2("C")).start();
new Thread(new Thread2("D")).start();
}
}
输出:
C运行 : 0
D运行 : 0
D运行 : 1
C运行 : 1
D运行 : 2
C运行 : 2
D运行 : 3
C运行 : 3
D运行 : 4
C运行 : 4
Thread2类通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序
的一个约定,所有的多线程代码都在run()方法里面,Thread类实际上也是实现了Runnable接口的类
Thread类和Runnable的区别: 如果一个类继承Thread,则不适合资源共享,但是如果实现了Runnable接口的话,则很容易实现资源共享(继承Thread类,同级执行,谁抢到CPU资源谁执行 实现Runnable接口时,一个 线程执行完一次,另一个线程执行,交叉执行,实现资源的共享)
实现Runnable接口比继承Thread类的优势: 1、适合多个相同的代码线程执行去处理同一个资源 2、可以避免java的单继承限制(一个类只能继承其他一个类,不可以多个继承) 3、增加程序的强健性,代码可以被多个线程共同使用,代码和数据都是独立的 4、线程池只能放入实现Runnable或callable类线程,不能直接放入继承Thread的类
注意:
main方法本身就是一个线程,在java中的线程是同时启动的,谁先执行,谁后执行,看得到CPU资源的顺序
在java中,每个程序的执行都至少启动两个线程,一个是main线程一个是垃圾收集线程,因为每当使用java命令启动一个程序的时候,实际上就是启动一个JVM,每一个JVM实际上
就是在操作一个进程
线程的状态转换: 创建---就绪---运行---阻塞---结束
线程的状态转换:
创建—就绪—运行—阻塞—结束
1、新建状态:新创建一个线程对象
2、就绪状态:线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于
可运行线程池中,变得可运行,等待获取CPU的使用权
3、运行状态:就绪状态获取了CPU资源,执行程序代码
4、阻塞状态:阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行,直到线程进入
就绪状态,才有机会转到运行状态
阻塞状态分为三种情况:
等待阻塞:运行的线程执行了wait()方法,JVM会把线程放入等待池中。(wait会释放持有的锁)
同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入
锁池中
其他阻塞:运行的线程执行sleep()或join()方法,或者发出I/O请求时,JVM会把该线程置为
阻塞状态。当sleep()状态超时,join()等待线程终止或者超时、后者I/O处理完毕时,线程重新转入
就绪状态(注:sleep是不会释放持有的锁)
5、死亡状态:线程执行完了或者异常退出run()方法,则该线程结束生命周期