进程:正在运行的程序称作为一个进程。进程负责了内存空间的划分
windows号称是多任务的操作系统,那么windows是同时运行多个应用程序么?
宏观角度:windows确实是在同时运行多个应用程序
微观角度:cpu是做了一个快速切换执行的动作,由于速度太快,所以我们感觉不到在切换而已
单核的cpu在一个时间片中只能执行一个应用程序
各个应用程序其实是在做cpu资源争夺战
线程:负责代码的执行
多线程:在一个进程中有多个线程在执行不同的任务
线程负责了代码的执行,以前没有线程,为什么代码可移执行?
任何一个java程序,jvm在运行的时候都会创建一main线程执行main方法中的所有方法
一个java应用程序至少有几个线程?
至少有两个线程,一个是主线程,负责main方法事物执行,一个是垃圾回收器,负责了回收垃圾。
与其说是进程在做cpu的资源争夺战,不如说是线程在做cpu的资源争夺战
多线程的好处:
1.解决了一个进程能同时执行多个任务的问题
2.提高了资源的利用率(将没有用尽资源利用起来)
弊端:
增加了CPU的负担
降低一个进程中线程的执行概率
会引发线程安全问题
出现死锁现象
如何创建多线程:
创建线程的方式:
方式一:
1.自定义一个类继承Tread类
2.重写Thread类的run方法
疑问:重写run方法的目的是什么?
每个线程都有自己的任务代码,jvm创建的主线程的任务代码就是main方法中的所有代码,自定义线程的任务代码就写在run方法中,自定义线程负责了run方法中代码
3.创建Thread的子类对象,并且调用start方法开启线程
一个线程一旦开启,那么线程就会执行run方法中的代码,run方法千万不能直接调用,直接调用run方法就相当于调用了一个普通方法而已
主线程和自定义线程是交替进行的
线程的生命周期:
cpu的等待资格
cpu的执行权
创建状态(将线程类对象new出来时):没有cpu等待资格,没有cpu执行权
(调用start方法)
可运行的状态(具备等待cpu的资格,不具备cpu的执行权)
(得到cpu的执行权,若被抢夺了cpu的执行权,返回上一状态)
运行状态(具备cpu的执行权,也具备cpu的等待资格)
(完成任务)
死亡状态(没有cpu的等待资格,没有cpu执行权)
临时阻塞状态(运行状态下的线程,一旦执行了sleep或者waitfangfa之后,那么该线程会进入临时阻塞状态下,如果线程是调用了sleep进入阻塞状态,那么线程一旦超过了指定的睡眠时间,就会重新进入可运行状态,如果调用了wait方法进入临时阻塞状态,那么需要该线程唤醒其他线程才可以重新进入可运行状态)不具备等待资格
线程常用的方法
thread(String name); 初始化线程的名字
getName() 返回线程的名字
setName(String name) 设置设置线程对象名
sleep() 线程睡眠指定的毫秒数 是一个静态的方法 哪个线程执行了sleep方法,那么就是哪个线程睡眠
getPriority() 返回当前线程的优先级 默认线程的优先级是5
setPriority(int newPriority) 设置线程的优先级 虽设置了线程的优先级,但是具体的实现取决于底层的操作系统的实现(最大的优先级是10,最小的是1,默认为5)
currentThread() 返回cpu正在执行的线程对象 该方法是一个静态方法,注意:哪个线程执行了currentThread()代码,就返回那个线程的对象
thread 子类 的run方法为什么不能抛出异常?
因为thread类的run方法没有抛出异常,所以继承父类的子类也不能抛出异常,run方法属于重写,重写的方法抛出的异常要小于或者等于父类抛出的异常
非静态的成员变量,非静态的成员变量数据是在每个对象中都会维护一份数据的
在什么情况下会出现线程安全问题:
1.存在两个或者两方以上的线程,并且线程之间共享一个数据资源
2.有多个语句操作共享资源
多线程的好处:
1.解决了一个进程中可以同时执行多个任务的问题
2.提高了资源的利用率
多线程的弊端:
1.增加了cpu的负担
2.降低了一个进程中线程的执行效率
3.出现了线程安全问题
4.会引发死锁现象
线程安全问题的解决方案:sun提供了线程同步机制让我们解决这类问题
java线程同步机制的方式:
方式一:同步代码块:
同步代码块的格式:
synchronized(锁对象){
需要被同步的代码
}
同步代码块要注意的事项:
1.锁对象可以是任意的一个对象,
任意的对象都可以作为锁对象。凡是对象内部都维护了一个状态的,java同步机制就是使用了对象中的状态作为了锁的标识 (用一个字符串也可以锁住)
2.在同步代码块中调用了sleep方法并不释放锁对象
3.只有真正存在线程安全问题的时候才使用同步代码块,否则会降低效率
4.多线程操作的锁对象必须是唯一共享的,否则无效
方式二:同步函数 使用synchronized修饰一个函数
同步函数的注意事项:
1.如果是一个非静态的同步函数的锁 对象是this对象 如果是静态的同步函数的锁 对象是当前函数所属的类的字节码文件(class对象)(在方法区创建一个对象后,系统将相应类进行分解,得到的方法属性封装到一个class对象上)
推荐使用:同步代码块
原因:
1.同步代码块的锁对象可以由我们随意指定,方便控制。同步函数的锁对象是固定的,不能由我们来指定。
2.同步代码块可以很方便控制需要被同步代码的范围,同步函数必须是整个函数的所有代码都被同步了。
java中的同步机制,解决了线程中的安全问题,也同时引发了死锁现象
死锁现象 出现的根本原因::
1.存在两个或者两个以上的线程
2.存在两个或者两个以上的共享资源
死锁解决的方案:没有方案,只能尽量避免的发生
自定义线程的创建方式二:
1.自定义一个类实现runnable接口
2.实现Runnable接口的run方法,把自定义线程的任务定义在run方法上
3.创建runnable的实现类对象,
4.创建thread类的对象,并且把Runnable实现类的对象作为一个参数传递进行
5.调用thread对象的start方法开启一个线程
问题1:请问runnable实现类的对象是线程对象吗?-------线程必须有start方法
Runnable实现类的对象并不是一个线程对象,只不过是实现了Runnable接口的对象而已
只有Thread及thread的对象才是属于线程对象
问题2:为什么要把runnable实现类的对象作为实参传递给Thread对象?作用是什么?
作用是把Runnable实现类的对象的run方法作为了线程的任务代码去执行
自定义线程的创建,推荐第二种。实现Runnable接口的
原因:因为java是单继承多实现的