1. 程序(Program)
语言编写的指令集合,指一段静态的代码。
2. 进程(Process)
动态的,一个正在运行的程序,及程序的一次执行过程,存在生命周期。可并发多个线程,每条线程执行不同任务
进程的三种状态
1. 就绪态
2. 运行态
3. 阻塞态
3. 线程(Thread)
进程中的一个单一顺序的控制流,作为调度和执行的最小单位,每个线程都拥有独立的运行栈和程序计数器,切换的开销小,共享同一个进程中的结构(方法区、堆)
线程的六种状态
1. New(新建)
2. Runnable(可运行)
3. Blocked(阻塞)
4. Waiting(等待)
5. Timed Waiting(计时等待)
6. Terminated(终止)

Java中的线程分为两类:守护线程和用户线程,若Java虚拟机中只剩下守护线程,那么Java虚拟机将退出。每个线程都有一个优先级,范围在1~10之间,默认线程的优先级为5
多任务(同时运行多个程序)是操作系统的能力,由操作系统为每个进程分配CPU时间片,由于时间延迟很低,给人一种并行处理的感觉。
多线程在更低一层扩展了多任务的概念,单个程序运行多个任务,一个程序同时运行多个线程,那么这个程序就是多线程程序。例如:服务器并发请求,浏览器同时下载多张图片。
多线程和多进程的区别是每个进程都有自己的一套变量,而线程之间则是共享数据。
线程的效率比进程高,但是安全性差
线程开始运行之后并不一定始终保持运行,抢占式调度系统给每一个可运行线程一个时间片来执行任务,当时间片用完时操作系统将剥夺该线程的运行权,同时考虑优先级,给另一个线程运行机会。
4. 堆
线程安全:本质是内存安全,因为堆是共享内存,可以被所有线程访问,当多个线程访问同一个对象时,如果不用进行额外的同步控制或协调操作,调用这个对象的行为都可以获得正确的结果,就称这个对象是线程安全的。
堆是进程和线程共有的空间,在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是用完了要还给操作系统,要不然就是内存泄漏。
堆分为全局堆和局部堆。
全局堆 | 局部堆 |
---|---|
所有没有分配的空间 | 用户分配的空间 |
在Java中,堆是虚拟机所管理的内存中最大的一块,是所有线程共享的一块内存区域,在虚拟机启动时创建。堆所存在的内存区域目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。
5. 栈
栈是每个线程独有的,保存其运行状态和局部变量。
栈在线程开始时初始化,每个线程的栈互相独立,因此,栈是线程安全的。操作系统在切换线程的时候会自动切换栈。栈空间不需要显式的分配和释放。
目前主流操作系统都是多任务的,即多个进程同时运行。为了保证安全,每个进程只能访问分配给自己的内存空间,而不能访问别的进程的,这是由操作系统保障的。
6. 同步
在多线程应用中,两个或两个以上线程在进行同一个对象数据存取时就会出现相互覆盖,这样对象就会被破坏,出现线程安全问题,这种情况称为竟态条件。这时就会用到同步来进行解决。
锁对象 synchronized 关键字,提供一个锁和相关的条件,确保任何时刻只有一个线程进入临界区,一个线程锁定对象后,当其他线程进行调用时会暂停,一直到到释放这个被锁住的对象。
synchronized (同步监视器){
同步监视器(锁):任何一个类的对象,多个线程必须共用同一把锁
同步代码块
}
7. 异步
public class MyThread extends Thread {
// 继承后可进行多线程 但是不常用
public void run() {
while (true) {
// 死循环无线运行
System.out.println("我是Thread的单线程run(),遇到死循环只会执行我");
}
}
public static void main(String[] args) {
// TODO thread类的 单线程
MyThread myThread = new MyThread();
// myThread.run();
// 多线程
myThread.start();// 开启线程,并且会自动调用run()
while (true) {
System.out.println("我是多线程才会执行的");
}
}
}
public class Run {
public String toString() {
return "重写Object的toString方法";
}
public void time() {
System.out.println("你可以得到一个程序运行时间");
}
public static void main(String[] args) throws Exception {
Runtime a = Runtime.getRuntime();// 需要创建一个对象
System.out.println(a.toString());
// a.exec("notepad.exe");//exec这个方法调用程序,相当于在cmd里输入命令
Process process = a.exec("notepad.exe");// 得到进程的一个对象,打开笔记本
Thread.sleep(3000);// 运行三秒
process.destroy();// 杀掉此进程
System.out.println("处理器个数" + a.availableProcessors() + "\n" + "空闲内存" + a.freeMemory() / 1024 / 1024 + "M");
System.gc();// 运行垃圾回收器进行垃圾回收
System.out.println(System.getProperties());// 获取当前系统的全部属性
// 获取运行时间
long start = System.currentTimeMillis();
Run b = new Run();
for (int i = 0; i < 1000; i++) {
b.time();
}
long end = System.currentTimeMillis();
System.out.println("运行时间为:" + (end - start) + "毫秒");
// 该值表示当前时间与1970/1/1/0:0:0的时间差//单位是毫秒,称为时间戳
}
}
/**
* 什么是线程 一个人在同一时间可以干很多不同的事,吃饭的同时可以看电视聊天 计算机在放音乐时可以复制文件 打印文档等等 进程 可以泛指每个独立正在执行的程序
* 每个进程中都会至少存在一个线程 由于java只支持单继承 无法进行继承一个父类后再继承Thread类 所以有Runnable接口
*/
public class Ticket implements Runnable {
int tickets = 10;
// 线程运行需要重写run方法
@Override
public void run() {
while (true) {
sendTicket();
}
}
public synchronized void sendTicket() {
// synchronized 同步锁 修饰 多线程同步
try {
Thread.sleep(10);// 线程休眠 在指定的毫秒时间内暂停
// Thread.yield();//线程让步
} catch (Exception e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "---卖出的票" + tickets--);
} else {
System.exit(0);
}
}
public static void main(String args[]) {
Ticket task = new Ticket();
new Thread(task,"一号窗口").start();//开启线程
new Thread(task,"二号窗口").start();
new Thread(task,"三号窗口").start();
new Thread(task,"四号窗口").start();
}
}