一、何为程序
1.概念
程序: 为了让计算机执行某些操作或者解决某个问题而编写的一系列有序指令的集合
2.举个银行取款的例子来说
完成取款的这个过程就是一个程序,取款包括 1)插卡 2)输入密码并完成验证 3)取出金额。
二、何为进程
1.概念
进程是具有一定独立功能的程序关于某个数据集合上的一次活动,进程是操作系统分配资源的一个独立单位。非正式的说法,进程就是执行中的程序。
2. 比如上面银行取款的例子,1)2)3)就是三个进程,进程是依次单个顺序进行的,也就是要完成了1)才能依次进行2)3)。
注意:程序本身不是进程,程序是被动实体,而进程是活动实体。
三、 何为线程
1.概念
线程时cpu使用的基本单元,它由线程ID、程序计数器、寄存器集合和栈组成,与属于同一进程的其他线程共享代码段、数据段和其他操作系统资源。
四、 线程和进程的关系
线程是进程划分为更小的额运行单位,一个进程可以有多个线程,而一个线程只能是属于一个进程;各进程之间是独立的,互不影响的,而同一进程下的线程会相互影响,不同进程下的线程是互不影响的。
五、多线程
1.概念
多线程就是同时执行多个线程。
2.优点
①多线程响应度高。如何一个程序采用多线程,那么即使某部分堵塞或者是执行时间较冗长。此程序扔可以进行。比如当你做饭的时候,创建了一个煮饭的线程,这时候你可以同时去创建进行另一个线程,无需等待前一个线程的完成。
②资源共享。同一进程下的线程默认共享该进程的内存和资源。
③经济。进程创建所需要的内存和资源分配比较昂贵。而线程能够共享它们所属的进程的资源,创建和切换都会更经济。创建进程花费的时间也比创建线程多。
3.模型
前言:提供线程支持的两种方法为用户层面的用户进程或者内核层面的内核线程。用户线程受内核支持,而无需内核管理;内核线程由操作系统直接支持和管理。
(a)多对一模型:将多个用户映射到一个内核线程。
优点:线程管理是在用户空间进行的,因而效率比较高。
缺点:当一个线程在使用内核服务时被阻塞,那么整个进程都会被阻塞;多个线程不能并行地运行在多处理机上。
(b)一对一:将每个用户映射到一个内核线程。
优点:当一个线程被阻塞后,允许另一个线程继续执行,所以并发能力较强。
缺点:每创建一个用户级线程都需要创建一个内核级线程与其对应,这样创建线程的开销比较大,会影响到应用程序的性能。
(c)多对多:将许多用户映射到同样数量或者更少数量的内核线程。
特点:在多对一模型和一对一模型中取了个折中,克服了多对一模型的并发度不高的缺点,又克服了一对一模型的一个用户进程占用太多内核级线程,开销太大的缺点。又拥有多对一模型和一对一模型各自的优点,可谓集两者之所长。
六、如何使用多线程
1.继承Thread类,重载run()函数(不直接调用run函数,而是调用start函数,然后再用它来调用run函数)
package thread0309;
public class Mythread extends Thread{
//重载run()
public void run()
{
super.run();
System.out.println("This is Mythread");
}
}
package thread0309;
public class Main {
public static void main(String[] args) {
Mythread mythread = new Mythread();
mythread.start();
System.out.println("运行结束");
}
}
运行结果
2.实现Runable接口(),前提是在执行Runable时,需要定义run()函数
(不直接调用run函数,而是调用start函数,然后再用它来调用run函数)
public class Mythread implements Runnable{
//重载run()
public void run()
{
System.out.println("Runnable");
}
}
package thread0309;
public class Main {
public static void main(String[] args) {
Mythread mythread = new Mythread();
Thread thread = new Thread(mythread);
thread.start();
System.out.println("运行结束");
}
}
结果
七、 共享数
1.不共享数据时
package thread0309;
public class Mythread extends Thread{
private int count = 5;
public Mythread(String name)
{
super();
this.setName(name);
}
//重载run()
public void run()
{
super.run();
while(count > 0)
{
count --;
System.out.println(this.currentThread().getName() + "计算 count = " + count);
}
}
}
package thread0309;
public class Main {
public static void main(String[] args) {
Mythread a = new Mythread("A");
Mythread b = new Mythread("B");
Mythread c = new Mythread("C");
a.start();
b.start();
c.start();
//Mythread mythread = new Mythread();
//Thread thread = new Thread(mythread);
//thread.start();
System.out.println("运行结束");
}
}
结果
可以看到线程abc都各自有自己的count值(4-3-2-1-0),并不互相影响
2.共享一个对象的数据
package thread0309;
public class Mythread extends Thread{
private int count = 5;
public Mythread(String name)
{
super();
this.setName(name);
}
//重载run()
public void run()
{
super.run();
while(count > 0)
{
count -- ;
System.out.println(this.currentThread().getName() + "计算 count = " + count);
}
}
}
package thread0309;
public class Main {
public static void main(String[] args) {
Mythread mythread = new Mythread("mythread");
//下列线程都是通过mythread对象创建的
Thread a = new Thread(mythread,"A");
Thread b = new Thread(mythread,"B");
Thread c = new Thread(mythread,"C");
a.start();
b.start();
c.start();
System.out.println("运行结束");
}
}
结果
可以看出这里已经出现了错误,因为在大多数jvm中,count–的操作分为如下下三步:
取得原有count值
计算i -1
对i进行赋值
所以多个线程同时访问时出现问题就是难以避免的了。