1.线程、进程
1.1 概念
进程:引入:为了程序能够并发执行,且为了对并发执行的程序加以描述和控制,引入了进程的概念。
(1)进程是程序的一次执行。
(2)进程是一个程序及其数据在处理机上顺序执行时所发生的活动。
(3)进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。
(4)进程是作为能够拥有资源和独立运行的基本单位。
线程: 引入:在操作系统中引入线程,是为了减少程序并发执行时锁付出的空间开销,使OS具有更好的并发性。1.2
1.2 线程与进程进行比较
线程具有许多传统进程所具有的特征,所以又称为轻量级进程或进程元,相应的把进程称为重量级的进程,传统进程相当于只有一个线程的任务,在引入了新城的操作系统中,通常一个进程都拥有若干个线程,至少也有一个线程。
相同点:
(1)调度:
(2)并发性:在引入了线程的操作系统中,进程之间或一个线程中的多个线程之间都可以并发执行。
(3)拥有资源:不论是传统的操作系统还是引入了线程的操作系统,进程都可以拥有资源,是系统中拥有资源的有个基本单位。
(4)系统开销:在某些操作系统中,线程的切换、同步和通信都无需操作系统内核的干预。
不同点:
(1)调度:在传统操作系统中,进程是拥有资源的基本和独立调度、分派的基本单位,在引入了线程的操作系统中,线程是调度和分派的基本单位,而进程是拥有资源的基本单位。
(2)并发性:
(3)拥有资源:进程拥有资源,线程自己不拥有资源(也有一点必不可少的资源)。但可以吧访问其他隶属进程的资源。
(4)系统开销:
a.在创建或撤销进程的时候,系统都要为之创建和回收进程控制块,分配或回收资源。如内存空间和I/O设备,系统开销明显大于线程创建或撤销时的开销。
b.在进程切换时,涉及到当前进程CPU环境的保存及新被调度运行进程的CPU环境的设置,而线程的切换则仅需要保存和设置少量寄存器内容,不涉及存储器管理方面的操作,所以,进程的代价远高于线程。
c.一个进程的多个线程具有相同的地址空间,在同步和通信的实现方面线程也比进程容易。
(5)进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
(6)进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮。
(7)每个独立的线程都有一个程序运行的入口,顺序执行序列和程序的入口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
1.3 线程的生命周期
1.3.1.线程处于就绪状态有以下几种方法
(1)调用sleep()方法
(2)调用wait()方法
(3)等待输入/输出完成
1.3.2.当线程处于就绪状态后,可以用以下几种方法使线程进入运行状态:
(1)线程调用notify()方法
(2)线程调用notifyAll()方法
(3)线程调用interrupt()方法
(4) 线程的休眠时间结束
(5)输入/输出结束
线程生命周期状态图:

2.线程的调度与控制
2.1 线程优先级
java虚拟机主要负责则线程的调度,获取CPU的使用权,目前有两种调度模型:分时调度模型和抢占调度模型;java使用抢占调度模型。
分时调度模型:所有线程轮流使用CPU的使用权,平均分配给每个线程占用CPU的时间片。
抢占调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么随机选择一个,优先极高的线程获得的CPU时间片相对多些。
例:


1 /*
2 线程优先级高的获取的时间片相对高
3 */
4 class Threadtest04
5 {
6 public static void main(String[] args)
7 {
8 //线程优先级
9 System.out.println(Thread.MAX_PRIORITY); //10 优先级最高
10 System.out.println(Thread.MIN_PRIORITY); //1 优先级最低
11 System.out.println(Thread.NORM_PRIORITY); //5 默认优先级
12 Thread t1 = new P();
13 t1.setName("t1");
14
15 Thread t2 = new P();
16 t2.setName("t2");
17
18 System.out.println(t1.getPriority()); //默认优先级为5
19 System.out.println(t2.getPriority()); //默认优先级为5
20 //设置优先级
21 t1.setPriority(4);
22 t2.setPriority(9);
23
24 System.out.println(t1.getPriority()); //默认优先级为5
25 System.out.println(t2.getPriority()); //默认优先级为5
26 //启动线程
27 t1.start();
28 t2.start();
29 }
30 }
31
32 class P extends Thread
33 {
34 public void run()
35 {
36 for(int i=0;i<10;i++)
37 {
38 System.out.println(Thread.currentThread().getName()+"..."+i);
39 }
40 }
41 }
42 /*
43 运行结果:
44 10
45 1
46 5
47 5
48 5
49 4
50 9
51 t1...0
52 t2...0
53 t1...1
54 t2...1
55 t1...2
56 t2...2
57 t1...3
58 t2...3
59 t1...4
60 t2...4
61 t1...5
62 t2...5
63 t1...6
64 t2...6
65 t1...7
66 t2...7
67 t1...8
68 t2...8
69 t1...9
70 t2...9
71 请按任意键继续. . .
72
73
74 */
View Code
2.2 sleep方法
sleep和wait的区别:
(1)所属类不同
Thread.sleep() ; Object.wait()
(2)对于线程已经占有资源的处理
sleep在休息的时候,不释放资源 ; wait在等待的时候释放自己占用的资源
例:


1 /*
2 1.thread.sleep(毫秒)
3 2.sleep方法是一个静态方法
4 3.该方法作用:阻塞当前线程,将CPU让给其他线程
5 */
6 class Threadtest05
7 {
8 public static void main(String[] args) throws InterruptedException
9 {
10 Thread t1 = new P();
11 t1.setName("t1");
12 t1.start();
13 Thread.sleep(5000);
14 //t1.interrupt();打断线程的睡眠
15 for(int i = 0;i<10;i++)
16 {
17 System.out.println(Thread.currentThread().getName()+".."+i);
18 Thread.sleep(500);//阻塞主线程0.5秒
19 }
20 }
21 }
22
23 class P extends Thread
24 {
25 //被重写的方法不能抛出异常,在run方法的声明为置上不能呢使用Throws,
26 public void run()
27 {
28 for(int i = 0;i<10;i++)
29 {
30
31 try{
32 Thread.sleep(1000);//让当前线程阻塞1s
33 }catch(InterruptedException e)
34 {
35 e.printStackTrace();
36 }
37 System.out.println(Thread.currentThread().getName()+".."+i);
38 }
39 }
40 }
41 /*
42 运行结果:
43 main..0
44 t1..0
45 main..1
46 t1..1
47 main..2
48 main..3
49 main..4
50 t1..2
51 main..5
52 t1..3
53 main..6
54 main..7
55 t1..4
56 main..8
57 main..9
58 t1..5
59 t1..6
60 t1..7
61 t1..8
62 t1..9
63 请按任意键继续. . .
64
65 */
View Code
2.3 yield方法
使用yield方法,与sleep方法类似,不能由用户指定暂停多长时间,并且yield方法只能让同优先级的线程由执行机会,让位时间不固定。静态方法。
2.4 Join方法
合并线程
3.创建线程的三种方法
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程,如下所示:
(1)继承Thread类创建线程
(2)实现Runnable接口创建线程
(3)使用Callable和Future创建线程
3.1.概念及特点
(1).概念
进程:计算机运行的应用程序。(多进程作用:提高CPU的使用率,不提高速度);
线程;一个进程中的执行场景,一个进程可以包多个线程。(多线程作用:提高应用程序的使用率,不提高速度)。
(2).内存特点
进程和进程之间的内存是独立的;
线程和线程共享“堆内存的方法区内存”,栈内存是独立的,一个线程一个栈。
(3).java程序的运行原理
Java命令启动Java虚拟机,启动JVM,等同于启动了一个应用程序,表示启动了一个进程,该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法,所 以main方法运行在主线程中。
3.2 线程的创建和启动
3.2.1 实现多线程的第一种方式
Thread类在包java.lang中,从这个类中实例化的对象代表线程,启动一个新线程需要建立Thread实例,Thread类中常用的两个构造方法如下:
(1)public Thread(String threadName)
(2)public Thread()
其中第一个构造方法是创建一个名称为threadName的线程对象
创建一个新的线程的语法如下:
public class ThreadTest extends Thread{}
完成线程真正功能的代码方法类run()方法中,当一个类继承Thread类后,就可以在该类中覆盖run方法,将实现该线程功能的代码写入run()方法中国,然后调用Thread类中的start()方法执行线程,即调用run()方法.
Thread对象需要一个任务来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写在run()方法中。当执行一个线程程序时,就自动产生一个线程,主方法是在这个线程上运次的,当不再启动其他线程时,该程序就为单线程程序。
以下是一个Thread类的实例:
/**
* 类ThreadTest继承继承Thread雷诺方法创建线程
* @author z
*
*/
public class ThreadTest extends Thread {
private int count = 10;
public void run(){
while(true){
System.out.println(count+"");
if(--count == 0){
return;
}
}
}
public static void main(String[] args){
new ThreadTest().start();
}
}
运行结果:10 9 8 7 6 5 4 3 2 1
分析:
在上例中,继承了Thread类,然后覆盖了run()方法,通常在run()方法中使用无限循环的形式,使得线程一直运行下去,所以要指定一跳出循环的条件,本例使用变量count递减为0的方法跳出循环条件。
在main()方发中,使线程执行需要调用Thread类中的start()方法,start()方法调用被覆盖的run()方法,如果不调用start()方法,线程永远不会启动,在主方法没有调用stsrt()方法之前,Thread()对象只是一个实例,而不是一个正真的线程。
再举一个例子:
第一步: 继承Java.lang.Thread
第二步;重写run方法
例:


1 class Threadtest01
2 {
3 public static void main(String[] args) //main方法在主线程
4 {
5 //1.创建线程
6 Thread t = new p();
7 //2.启动线程
8 t.start(); /*启动t线程,执行后,t线程瞬间结束,JVM再分配一个新的栈给t线程
9 run方法不需要手动调用,系统线程启动之后自动调用run方法。*/
10
11 for(int i=0;i<100;i++) //在主线程中运行
12 {
13 System.out.println("main....."+i);
14 }
15 }
16 }
17 /*
18 在多线程中,main方法结束后只是主线程踪没有方法栈帧了,但
19 其他线程中或者其他栈中还有栈帧,main方法结束,程序可能还在运行
20 */
21
22 //3.定义一个线程
23 class p extends Thread
24 {
25 //重写run方法
26 public void run ()
27 {
28 for(int i=0;i<100;i++)
29 {
30 System.out.println("run...."+i);
31 }
32 }
33 }
34 /*
35 运行部分结果如下:
36 main.....0
37 main.....1
38 main.....2
39 run....0
40 main.....3
41 run....1
42 main.....4
43 run....2
44 main.....5
45 run....3
46 main.....6
47 run....4
48 main.....7
49 run....5
50 main.....8
51 run....6
52 */
View Code
上述代码的图解如下:

3.3.2 实现多线程的第二种方式:
Runnable接口的说用是使线程不仅可以继承Thread类实现,还可以继承其他类(比如:JFrame)。
此接口具有两个构造方法:
(1)public Thread(Runnable r)
(2)public Thread(Runnable r,String name).
这两个构造方法的参数中都存在Runnable实例,使用构造方法就可以将Runnable实例与Thread实例相关联。
使用Runnable的步骤如下:
(1)建立Runnable对象
(2)使用参数为Runnable对象的构造方法创建Thread实例
(3)调用start()方法。
例:在项目中创建SwingAndThread类,该类继承了JFrame类,实现图标移动的功能,其中使用了Swing与线程相结合的技术:


1 import java.awt.*;
2 import java.net.*;
3
4 import javax.swing.*;
5
6 public class SwingAndThread extends JFrame {
7 /**
8 *
9 */
10 private static final long serialVersionUID = 1L;
11 private JLabel jl = new JLabel(); // 声明JLabel对象
12 private static Thread t; // 声明线程对象
13 private int count = 0; // 声明计数变量
14 private Container container = getContentPane(); // 声明容器
15
16 public SwingAndThread() {
17 setBounds(300, 200, 250, 100); // 绝对定位窗体大小与位置
18 container.setLayout(null); // 使窗体不使用任何布局管理器
19 URL url = SwingAndThread.class.getResource("/1.gif"); // 获取图片的URL
20 Icon icon = new ImageIcon(url); // 实例化一个Icon
21 jl.setIcon(icon); // 将图标放置在标签中
22 // 设置图片在标签的最左方
23 jl.setHorizontalAlignment(SwingConstants.LEFT);
24 jl.setBounds(10, 10, 200, 50); // 设置标签的位置与大小
25 jl.setOpaque(true);
26 t = new Thread(new Runnable() { // 定义匿名内部类,该类实现Runnable接口
27 public void run() { // 重写run()方法
28 while (count <= 200) { // 设置循环条件
29 // 将标签的横坐标用变量表示
30 jl.setBounds(count, 10, 200, 50);
31 try {
32 Thread.sleep(1000); // 使线程休眠1000毫秒
33 } catch (Exception e) {
34 e.printStackTrace();
35 }
36 count += 4; // 使横坐标每次增加4
37 if (count == 200) {
38 // 当图标到达标签的最右边,使其回到标签最左边
39 count = 10;
40 }
41 }
42 }
43 });
44 t.start(); // 启动线程
45 container.add(jl); // 将标签添加到容器中
46 setVisible(true); // 使窗体可视
47 // 设置窗体的关闭方式
48 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
49 }
50
51 public static void main(String[] args) {
52 new SwingAndThread(); // 实例化一个SwingAndThread对象
53 }
54 }
View Code
运行结果:

再举一个例子:
第一步:写一个实现类java,lang.Runnable;接口
第二步:实现run方法
例:


1 package test;
2
3 class Main
4 {
5 public static void main(String[] args)
6 {
7 //创建线程
8 Thread t = new Thread(new p());
9 //启动线程
10 t.start();
11 for(int i = 0;i<100;i++)
12 System.out.println("mian..."+i);
13
14 }
15 }
16 //优先,一个类实现接口之外保留了类的继承
17 class p implements Runnable
18 {
19 public void run()
20 {
21 for(int i = 0;i<100;i++)
22 System.out.println("run..."+i);
23 }
24 }
25 /*
26 * 部分运行结果:
27 * run...8
28 mian...10
29 run...9
30 mian...11
31 run...10
32 mian...12
33 run...11
34 mian...13
35 run...12
36 */
View Code
4.线程的同步(加锁)
4.1 基本概念及特点
(1)概念:
a.线程同步,是指某一个时刻,只允许一个线程访问共享资源,线程同步实际上是对对象加锁,如果对象中的方法都是同步方法,那么某一时刻只能执 行一个方法,采用线程同步解决以上问题; 为了数据安全,尽管应用程序的使用效率降低,但是为了数据安全,必须加入线程同步机制,线程同步机制使程序等同于单线程。
b.异步编程模型:多个线程分别执行,各线程互不影响。
c.同步编程模型:多个线程执行只有一个线程执行结束才能执行另一个线程。(作用:达到数据安全)
(2)使用线程同步机制的条件:
a:必须是多线程环境
b:多线程环境共享一个数据
c:共享的数据涉及到数据的修改
4.2 举例
例1:(对象锁,方法一,控制精确,常用)


1 /*
2 模拟银行取款系统:对于同一个账号,用两个线程同时对其取款。
3 */
4 class Threadtest06
5 {
6 public static void main(String[] args)
7 {
8 //创建公共账号
9 Account act = new Account("账号sss",10000);
10 //创建两个线程对同一个账户取款
11 Thread t1 = new Thread(new P(act));
12 Thread t2 = new Thread(new P(act));
13 t1.start();
14 t2.start();
15 }
16 }
17 //取款线程
18 class P implements Runnable
19 {
20 //账户
21 Account act;
22 P(Account act)
23 {
24 this.act = act;
25 }
26 public void run()
27 {
28 act.withdraw(2000);
29 System.out.println("取款成功,余额为:"+act.getBalance());
30 }
31
32 }
33 //账户
34 class Account
35 {
36 private String action;
37 private double balance;
38 public Account(){}
39 public Account(String action,double balance){
40 this.action = action;
41 this.balance = balance;
42 }
43 public void setAction(String action)
44 {
45 this.action = action;
46 }
47
48 public void setBalance(double balance)
49 {
50 this.balance = balance;
51 }
52 public String getAction(String action)
53 {
54 return action;
55 }
56 public double getBalance()
57 {
58 return balance;
59 }
60 public void withdraw(double money)
61 {
62 synchronized(this){ //this表示共享对象
63 double after = balance - money;
64 try{
65 Thread.sleep(1000);
66 }catch(Exception e){}
67 this.setBalance(after);
68 }
69 }
70 }
71
72 /*
73 运行结果:
74 取款成功,余额为:8000.0
75 取款成功,余额为:6000.0
76 请按任意键继续. . .
77
78 */
View Code
上例原理: t1线程执行到synchronized关键字处,就会去找this对象锁,如果找到this对象锁,就回进入同步语句块中执行,当同步语句块中的代码执行结束后,
t1线程归还this对象锁。在t1线程执行同步语句块的过程中,如果t2线程也过来执行此代码,也遇到synchronized关键字,所以也去找this对象锁,但是
该对象锁被t1线程持有,只能等待this对象的归还。
例2;synchronized关键字添加到成员方法上,线程拿到的扔是this的对象锁(对象锁,方法二,执行效率低)


1 /*
2 模拟银行取款系统:对于同一个账号,用两个线程同时对其取款。
3 */
4 class Threadtest06
5 {
6 public static void main(String[] args)
7 {
8 //创建公共账号
9 Account act = new Account("账号sss",10000);
10 //创建两个线程对同一个账户取款
11 Thread t1 = new Thread(new P(act));
12 Thread t2 = new Thread(new P(act));
13 t1.start();
14 t2.start();
15 }
16 }
17 //取款线程
18 class P implements Runnable
19 {
20 //账户
21 Account act;
22 P(Account act)
23 {
24 this.act = act;
25 }
26 public void run()
27 {
28 act.withdraw(2000);
29 System.out.println("取款成功,余额为:"+act.getBalance());
30 }
31
32 }
33 //账户
34 class Account
35 {
36 private String action;
37 private double balance;
38 public Account(){}
39 public Account(String action,double balance){
40 this.action = action;
41 this.balance = balance;
42 }
43 public void setAction(String action)
44 {
45 this.action = action;
46 }
47
48 public void setBalance(double balance)
49 {
50 this.balance = balance;
51 }
52 public String getAction(String action)
53 {
54 return action;
55 }
56 public double getBalance()
57 {
58 return balance;
59 }
60 public synchronized void withdraw(double money)
61 {
62
63 double after = balance - money;
64 try{
65 Thread.sleep(1000);
66 }catch(Exception e){}
67 this.setBalance(after);
68
69 }
70 }
71
72 /*
73 运行结果:
74 取款成功,余额为:8000.0
75 取款成功,余额为:6000.0
76 请按任意键继续. . .
77
78 */
View Code
(另:StirngBuffer Vector Hashtable 是线程安全的 )
5.死锁
例:


1 /*
2 死锁
3 */
4 class DeadLook
5 {
6 public static void main(String[] args)
7 {
8 Object o1 = new Object();
9 Object o2 = new Object();
10
11 Thread t1 = new Thread(new T1(o1,o2));
12 Thread t2 = new Thread(new T2(o1,o2));
13 t1.start();
14 t2.start();
15 }
16 }
17
18 class T1 implements Runnable
19 {
20 Object o1;
21 Object o2;
22 T1(Object o1,Object o2)
23 {
24 this.o1 = o1;
25 this.o2 = o2;
26 }
27 public void run()
28 {
29 synchronized(o1)
30 {
31 try{Thread.sleep(1000);}catch(Exception e){}
32 synchronized(o2)
33 {
34 System.out.println("t1");
35 }
36 }
37 }
38 }
39 class T2 implements Runnable
40 {
41 Object o1;
42 Object o2;
43 T2(Object o1,Object o2)
44 {
45 this.o1 = o1;
46 this.o2 = o2;
47 }
48 public void run()
49 {
50 synchronized(o2)
51 {
52 try{Thread.sleep(1000);}catch(Exception e){}
53 synchronized(o1)
54 {
55 System.out.println("t2");
56 }
57 }
58 }
59 }
View Code
6.守护线程
从线程的分类上可以分为:用户线程和守护线程,所有的用户线程结束生命周期,只有一个用户线程存在,那么守护线程就不会结束,Java中的垃圾回收器就
是一个守护线程,只有应用程序中所有的线程结束,它才会结束。
例:


1 /*
2 守护线程:
3 所有的用户线程结束,守护线程才会结束,守护线程是一个无限循环执行的。
4 */
5 class Threadtest08
6 {
7 public static void main(String[] args) throws Exception
8 {
9 Thread t1 = new P();
10 t1.setName("t1");
11 t1.setDaemon(true);//将用户线程修改为守护线程
12 t1.start();
13 //主线程
14 for(int i = 0;i < 10; i++)
15 {
16 System.out.println(Thread.currentThread().getName()+".."+i);
17 Thread.sleep(1000);
18 }
19 }
20 }
21
22 class P extends Thread
23 {
24 public void run()
25 {
26 int i = 0;
27 while(true)
28 {
29 i++;
30 System.out.println(Thread.currentThread().getName()+".."+i);
31 try{Thread.sleep(1000);}catch(Exception e){}
32 }
33 }
34 }
35 /*
36 运行结果:
37 main..0
38 t1..1
39 t1..2
40 main..1
41 t1..3
42 main..2
43 main..3
44 t1..4
45 main..4
46 t1..5
47 main..5
48 t1..6
49 main..6
50 t1..7
51 main..7
52 t1..8
53 main..8
54 t1..9
55 main..9
56 t1..10
57 请按任意键继续. . .
58
59
60 */
View Code
7.Timer定时器
作用:每隔一段固定的时间执行一段代码
例:


1 /*
2 定时器
3 */
4 import java.text.*;
5 import java.util.*;
6 class Timertest
7 {
8 public static void main(String[] args) throws Exception
9 {
10 //创建定时器
11 Timer t = new Timer();
12 //指定定时任务
13 t.schedule(new LogTimerTask(),new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").parse("2017-04-21 11:42:00 000"),10*1000);
14
15 }
16 }
17 //指定任务
18 class LogTimerTask extends TimerTask
19 {
20 public void run()
21 {
22 System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
23 }
24 }
View Code
8.线程池
参考资料 http://www.importnew.com/19011.html
http://lavasoft.blog.51cto.com/62575/27069/
https://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&mid=2247484346&idx=1&sn=f065ebd404771a90988bb097ea4e26dd&chksm=e9c5fa0bdeb2731d12b838372fc8aa97890dd2e3379d1a486df7cf795f8a1538c1ae974a13e7&mpshare=1&scene=23&srcid=1022Iecc2i96j9Drfxgzd274#rd
(1)调度:在传统操作系统中,进程是拥有资源的基本和独立调度、分派的基本单位,在引入了线程的操作系统中,线程是调度和分派的基本单位,而进程是拥有资源的基本单位。
(2)并发性:
(3)拥有资源:进程拥有资源,线程自己不拥有资源(也有一点必不可少的资源)。但可以吧访问其他隶属进程的资源。
(4)系统开销:
a.在创建或撤销进程的时候,系统都要为之创建和回收进程控制块,分配或回收资源。如内存空间和I/O设备,系统开销明显大于线程创建或撤销时的开销。
b.在进程切换时,涉及到当前进程CPU环境的保存及新被调度运行进程的CPU环境的设置,而线程的切换则仅需要保存和设置少量寄存器内容,不涉及存储器管理方面的操作,所以,进程的代价远高于线程。
c.一个进程的多个线程具有相同的地址空间,在同步和通信的实现方面线程也比进程容易。
(5)进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
(6)进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮。
(7)每个独立的线程都有一个程序运行的入口,顺序执行序列和程序的入口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
参考资料 http://www.importnew.com/19011.html
http://lavasoft.blog.51cto.com/62575/27069/
https://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&mid=2247484346&idx=1&sn=f065ebd404771a90988bb097ea4e26dd&chksm=e9c5fa0bdeb2731d12b838372fc8aa97890dd2e3379d1a486df7cf795f8a1538c1ae974a13e7&mpshare=1&scene=23&srcid=1022Iecc2i96j9Drfxgzd274#rd
参考资料 http://www.importnew.com/19011.html
http://lavasoft.blog.51cto.com/62575/27069/
https://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&mid=2247484346&idx=1&sn=f065ebd404771a90988bb097ea4e26dd&chksm=e9c5fa0bdeb2731d12b838372fc8aa97890dd2e3379d1a486df7cf795f8a1538c1ae974a13e7&mpshare=1&scene=23&srcid=1022Iecc2i96j9Drfxgzd274#rd
来源:https://www.cnblogs.com/xyzyj/p/6159753.html