区别:
1、进程中包含线程,每一个进程都至少一个线程(主线程)
2、进程是申请系统资源的最小单位
3、进程是CPU调度的最小单位
4、线程之间共享进程申请的系统资源
5、一个线程崩溃了会影响整个进程
进程的组织方式:
通过一个双向链表组织PCB:
创建一个进程就是把PCB加入到链表中;
销毁一个进程就是把PCB从链表中删除;
查看所有的进程就是遍历双向链表。
线程概念及优势:
多进程能充分利用CPU资源去处理复杂业务,从而提高效率。
但是进程申请资源对系统的性能影响较大,涉及内存和文件资源,处理一个事情有一份资源就够了。
线程用的就是进程启动时从操作系统中分配的资源,(线程也可以叫轻量级的进程),当创建一个进程时,进程中就会包含一个线程,叫主线程。
我们可以理解为进程就是一个公司,线程就是员工,一个公司可以有多个员工,一个进程可以创建多个线程。
优势:
创建速度比进程快;
销毁速度比进程快;
线程的CPU调度速度比进程快。
线程的创建:
创建线程的个数,根据CPU逻辑处理器数量来作为参考。
通过多线程的方式可以提高效率,但当线程数量大于逻辑处理器数时,由于过多线程处于阻塞等待状态,不能真正发挥作用,反而因创建线程消耗系统资源。
当某一个线程出现问题,会影响其他线程,进而影响整个进程。
一个线程崩溃会导致整个进程崩溃。
线程的创建方式:
在JAVA中Thread类用来描述一个线程,创建的每个线程都是Thread类的对象
1、继承Thread类(线程对象),重写run()方法(线程要执行的具体任务)
public class Demo {
public static void main(String[] args) {
//线程的多种创建方式
//通过继承Thread类并重写run方法
MyThread t1 = new MyThread();
}
}
class MyThread extends Thread{
@Override
public void run(){
System.out.println("hello my Thread");
}
}
2、实现Runnable接口,重写run()方法
public class Demo_206 {
public static void main(String[] args) {
//线程的多种创建方式
//通过Runnable示例来单独定义线程的任务对象
MyRunnable r1 = new MyRunnable();
Thread thread = new Thread(r1);
}
}
class MyRunnable implements Runnable{
@Override
public void run(){
System.out.println("hello my Runnable");
}
}
更推荐第二种
简化的方式:
通过匿名内部类的方式,创建Thread的子类,Runnable的子类
public class Demo_206 {
public static void main(String[] args) {
//线程的多种创建方式
//通过创建Thread匿名内部类的方式创建线程
Thread thread1 = new Thread(){
@Override
public void run(){
System.out.println("通过Thread匿名内部类的方式创建线程");
}
};
//匿名内部类,Runnable
Thread thread2 = new Thread(new Runnable(){
@Override
public void run(){
System.out.println("匿名内部类,Runnable……");
}
});
}
}
通过Lambda表达式的方式,简洁方便
public class Demo_206 {
public static void main(String[] args) {
//线程的多种创建方式
//通过Lambda表达式创建一个线程
Thread thread3 = new Thread(()->{
System.out.println("通过Lambda表达式创建线程……");
});
}
}
多线程的优势:
能够增加运行速度。
通俗讲,
一个大的任务来分配给多个执行者来一起执行就会更快完成任务,进而提高效率;
设置一个场景,执行两次自增到10亿的操作,
单线程,串行执行任务;
多线程,这里设置两个线程,两个线程分别执行;
public class Demo {
//大数可以使用分隔符_
private static long count = 10_0000_0000l;
public static void main(String[] args) {
//串行
serial();
//并行
concurrency();
}
private static void concurrency(){
//记录开始时间
long begin = System.currentTimeMillis();
//创建两个线程,各自累加
Thread t1 = new Thread(()->{
long a = 0l;
for(int i = 0; i < count; i++){
a++;
}
});
t1.start();//启动线程
Thread t2 = new Thread(()->{
long b = 0l;
for(int i = 0; i < count; i++){
b++;
}
});
t2.start();//启动线程
long end = System.currentTimeMillis();
System.out.println("并行执行时间:"+ (end - begin));
}
private static void serial(){
//记录开始时间
long begin = System.currentTimeMillis();
long a = 0l;
for(int i = 0; i < count; i++){
a++;
}
long b = 0l;
for(int i = 0; i < count; i++){
b++;
}
//记录结束时间
long end = System.currentTimeMillis();
System.out.println("串行执行时间:" + (end - begin));
}
}
结果:
我们可以看到并行执行时间快很多,但是这并不是真的并行执行时间,
开始记录时间后创建了线程t1,然后开启t1,接着创建线程t2并开启该线程,然后就打印了执行时间,但此时两个线程还在执行任务,没有结束。
要想打印出真正的并行执行时间,可以让线程调用join()方法,哪个线程调用join方法,主线程就要等待该线程执行完它的任务
所以我们能够看出通过多线程的方式能够提高效率,并行的执行时间是串行的一半多一点,之所以多一点是由于创建线程还会耗时。
但并不是多线程的效率都比单线程高,当任务量很少时,由于多线程创建会耗时,单线程效率可能更高。
当把10亿换成5万后可以看到串行执行时间更短,效率更高