网上很多资料对多线程都有详细的描述与理解,本菜鸟刚刚入门JAVA对多线程方面不是很熟悉,在看过很多视屏,以及相关博客,书籍通过自己的语言来描述对JAVA多线程的理解,给一些和我一样的菜鸟一起交流,写的不好的地方请各位大神多多指正,互相学习,共同进步。
1.什么是多线程?
是指一个应用程序同时执行多个任务,一般来说一个任务就是一个线程 ,而一个应用程序有一个以上的线程我们称之为多线程。
2.什么是进程?
进程是一个正在执行的程序 ,比如QQ,迅雷等 一个进程的运行会向CPU申请在内存中开辟一个内存块。
他是向CPU申请资源的,进程之间数据相互独立,一个进程至少有一个线程。
3.什么是线程?
线程是进程中的单一的顺序控制流程也可以叫做最小控制单元,线程是进程中执行单元,开启一个线程比开启一个进程更加节省资源。
4.多线程与多进程的区别?
多进程拥有自己的一套数据变量,而多线程是共享数据,而共享数据也会带来一系列的安全问题(安全问题稍后再提)。
当然在这里既然说到多线程肯定要提出多线程中线程的七大状态
5.新建状态:
新建状态也就是我们所说的创建状态如 new Thread(r); 这个线程还没有运行,当一个线程还是新建状态的时候,程序还没有开始运行线程中的代码。
6.可运行状态(就绪状态):
一旦调用了Start()方法 那么线程就处与可以运行的状态,但是不是说这个线程会马上开始执行,而是根据操作系统来决定赋予它执行的权力,但是也不是说这个线程拿到执行的权力就一直会执行,在线程运行中可能线程会中断,从而将执行权力交给其他线程执行。采用的是抢占方式调度,给每一个线程一个时间片来执行任务,当时间片(所谓的时间片就是一定的时间内,只执行这个线程)时间到了,操作系统会根据其他线程的优先级(什么是线程的优先级我们后面会讲到)来赋予其他线程执行权力。
7.运行状态:当获取到CPU执行权力 开始正真的执行Run方法中的代码,这是运行状态。
**8.阻塞状态: **
什么是阻塞状态呢?,是指当一个线程想获取自己的一个内置的对象锁的时候,这个对象锁被其他线程所占用,该线程不能执行这个就是阻塞状态,除非当另外一个线程释放锁,并且操作系统允许它执行他才变为非阻塞状态。这个怎么理解呢其实锁是分为对象锁和类锁 每一个对象都有一个内置的锁 ,在遇到同步的方法或则同步块也就是 被Synchronized修饰的方法 或则使用synchronized的同步块,那么如果一个继承了Thread类或则实现了 Runnable接口的类 下面我们创建了两个线程 这两个线程是实例了相同类创建不同的两个对象,分别启动了开启线程方法start(),因为我们在run方法中加了同步块,而同步块的锁是这个类的类锁,所以只要是这个类的实例对象都可以得到这个锁,但是我们都知道类锁只有一把,那个线程先抢到,谁就拥有执行权力,等到这个线程执行完了,释放锁其他线程才能执行。 而没有得到锁的线程他的状态就是阻塞状态,等到拿到锁的线程执行完了,再把锁给它,它就是非阻塞状态了
public class ThreadTest extends Thread {
//标记线程号
private int threadNo;
//生成构造方法
public ThreadTest(int threadNo) {
this.threadNo = threadNo;
}
@Override
//同步方法默认同步对象
public void run() {
//可以把同步方法想成一个房屋,而同步代码块就是里面的保险箱 这个保险箱的钥匙可以是 这个房间的钥匙也可以是其他钥匙
//我们在这里加了一个类锁 ThreadTest.class 意思就是想进代码块必须是这个类是实例 但是类锁只有一个 所以造成了两个同步
// 每一个对象都有一个内置的锁 但是两个一个类的实例同时访问 这个类中的同步方法不会 同步,除非采用synchronized(){}代码块给类加锁
//因为我们创建的两个对象是有两把锁,每个对象一个 互相不干扰,除非给这个类加锁
synchronized(ThreadTest.class){
for (int i = 1; i < 10; i++) {
System.out.println(“第” + threadNo + “是” + i);
}
}
}
public static void main(String[] args) throws InterruptedException {
//开启两个线程同时执行
new ThreadTest(1).start();
new ThreadTest(2).start();
}
}
运行结果:
第1个是1
第1个是2
第1个是3
第1个是4
第1个是5
第1个是6
第1个是7
第1个是8
第1个是9
第2个是1
第2个是2
第2个是3
第2个是4
第2个是5
第2个是6
第2个是7
第2个是8
第2个是9
在这里看出两个线程是同步的
9.等待状态:
在调用Object.wait线程进入等待状态,这个等待状态必须是持有对象锁也就是进入同步方法或则同步块中调用不然会抛出IllegalMonitorStateException异常 这个方法如果被调用那么这个线程会自动释放对象锁并进入等待状态,除非有另外一个线程(持有对象锁)的线程,也就是说他在执行同步方法或则同步块代码中才能调用notify()或者notifyAll唤醒所有线程,那么该等待线程被唤醒并拥有可运行权力,并不是被唤醒就会得到对象锁马上运行,还是得看CPU老大给不给这个权力。
10.计时等待状态:
下面我们来说说计时等待状态,在很多面试题中都会有Object.wait和Thread.sleep方法有什么区别,其实在调用wait方法的时候进入等待状态线程没有执行权力,但是调用Sleep方法该方法接受一个毫秒数,这个单词翻译过来也就是休眠,可以这个样子说,一个线程在调用这个sleep方法后进行等待,但是他不会释放这个对象锁,也就是说要拿到这个对象锁的线程还是在 阻塞状态,但是不进入这个同步方法也就是不需要这个对象锁的线程还是可以继续执行,当休眠时间一到,马上继续执行 这个就是wait和sleep的区别 一个是放弃锁并进入等待,一个是不放弃锁,时间到了就开始执行,调用sleep()方法的线程状态也就是计时等待状态。
11.挂起状态:
挂起状态也叫做死亡状态,这种状态是指线程在执行完Run()方法中的代码 正常结束或则没有捕获异常(也就是发生异常了没有处理)而造成的线程结束。或则调用Stop()方法来杀死该线程不过Stop方法已经过时,而且不推荐使用。