进程:
是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程,从创建、运行到消亡的过程。
线程:
线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也成为多线程程序。
简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。
线程调度:
-
分时调度
所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。 -
抢占式调度
优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的就是抢占式调度。
详解:
实际上,CPU使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时间,只能执行一个线程,而CPU的在多个线程间切换速度相对于我们的感觉要快,看上去就是在同一时刻运行。其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU使用率更高。
创建线程的两种方式以及常用的方法
// 实现Runnable接口
public class RunImpl implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("RunImpl-->"+i);
}
}
}
// 继承Thread类
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(currentThread().getName()+"-->"+i);
}
}
}
public class Review1 {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(new RunImpl()).start();
mt.start();
for (int i = 0; i < 10; i++) {
System.out.println("main-->"+i);
}
}
}
实现Runnable接口比继承Thread类所具有的优势:
- 适合多个相同的程序代码的线程去共享同一个资源;
- 可以避免java中的单继承的局限性(即继承了一个类则无法再继承第二个类,如果一开始写固定了,用了继承这种方式,则后续再向拓展就没办法了,而接口可以避免这一点);
- 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。(主要就是解耦,用了多态的形式,想切换到哪个线程,只要改变父类引用指向的子类对象即可);
- 线程池只能放入实现Runnable或者Callable类线程,不能直接放入继承Thread的类。
扩充:在Java中,每次程序运行至少启动两个线程。一个是main线程,一个是垃圾收集线程。
线程同步的三个方法
- 同步代码块
// synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实现互斥访问
public class Ticket implements Runnable{
private int ticket = 100;
Object lock = new Object();/** 执行卖票操作*/
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){
synchronized (lock) {
if(ticket>0){
//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(50);
}
catch (InterruptedException e) {
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThreaSystem.out.println(name+"正在卖:"+ticket--);
}
}
}
- 同步方法
public synchronized void sellTicket(){
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖:"+ticket‐‐);
}
}
- 锁机制
public class Ticket implements Runnable{
private int ticket = 100;
Lock reentrantLock = new ReentrantLock();
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){
reentrantLock.lock();
if(ticket>0){
//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(50);
}
catch (InterruptedException e) {
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThreaSystem.out.println(name+"正在卖:"+ticket--);
}
reentrantLock.unlock();
}
}
}
下面说下几种线程状态
以上这些没必要死记硬背,理解就行,关键就是围绕着“锁”在竞争。