Java基础知识图解:
1、基本概念
(1)程序: 是为完成特定任务、用某种语言编写的一组指令的集合。即指一
段静态的代码
,静态对象。
(2)进程:是程序的一次执行过程,或是
正在运行的一个程序
。
是一个动态的过程:有自身的产生、存在和消亡的过程
进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
程序是静态的,进程是动态的
(3)线程:进程可进一步细化为线程,是一个程序内部的一条执行路径。
若一个进程同一时间
并行
执行多个线程,就是支持多线程的
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc)
,
线程切换的开销小
一个进程中的多个线程共享相同的内存单元/内存地址空间--->它们从同一堆中分配对
象,可以 访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程
操作共享的系统资源可能就会带来
安全的隐患
。
(4) 一个Java应用程序java.exe,其实至少有三个线程:main()主线程,gc() 垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。
(5)并行与并发:
并行:多个CPU同时执行多个任务
并发:一个CPU(采用时间片)同时执行多个任务。
2、线程的创建和使用
2.1
Java
语言的
JVM
允许程序运行多个线程,它通过
java.lang.Thread
类来体现。
Thread
类的特性
每个线程都是通过某个特定Thread
对象的
run()
方法来完成操作的,经常
把
run()
方法的主体称为
线程体
通过该Thread
对象的
start()
方法来启动这个线程,而非直接调用
run()
Thread
类
(1)构造器
Thread()
:
创建新的
Thread
对象
Thread(String threadname)
:
创建线程并指定线程实例名
Thread(Runnable target):
指定创建线程的目标对象,它实现了
Runnable
接
口中的
run
方法
Thread(Runnable target, String name)
:
创建新的
Thread
对象
2.2 API
中创建线程的两种方式
1、
JDK1.5
之前创建新执行线程有两种方法:
继承
Thread
类的方式
实现
Runnable
接口的方式
2、方式一:继承
Thread类的方式
1)
定义子类继承
Thread
类。
2)
子类中重写
Thread
类中的
run
方法。
3)
创建
Thread
子类对象,即创建了线程对象。
4)
调用线程对象
start
方法:启动线程,调用
run
方法。
注意:
(1)如果自己手动调用
run()
方法,那么就只是普通方法,没有启动多线程模式。
(2) run()
方法由
JVM
调用,什么时候调用,执行的过程控制都有操作系统的
CPU
调度决定。
(3)想要启动多线程,必须调用
start
方法。
(4)一个线程对象只能调用一次
start()
方法启动,如果重复调用了,则将抛出以上的异常“IllegalThreadStateException
”。
3、方式二:
实现
Runnable
接口
1)
定义子类,实现
Runnable
接口。
2)
子类中重写
Runnable
接口中的
run
方法。
3)
通过
Thread
类含参构造器创建线程对象。
4)
将
Runnable
接口的子类对象作为实际参数传递给
Thread
类的构造器中。
5)
调用
Thread
类的
start
方法:开启线程,调用
Runnable
子类接口的
run
方法。
4、两种方式的区别与联系
public class
Thread
extends
Object
implements
Runnable
区别
继承
Thread
:线程代码存放
Thread
子类
run
方法中。
实现
Runnable
:线程代码存在接口的子类的
run
方法
实现方式的好处
避免了单继承的局限性
多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。
5、Thread
类的有关方法
void start():
启动线程,并执行对象的
run()
方法
run():
线程在被调度时执行的操作
String getName():
返回线程的名称
void setName(String name)
:
设置该线程名称
static Thread currentThread():
返回当前线程。在
Thread
子类中就是this
,通常用于主线程和
Runnable
实现类
static void yield()
:
线程让步
暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
若队列中没有同优先级的线程,忽略此方法
join()
:
当某个程序执行流中调用其他线程的
join()
方法时,调用线程将被阻塞,直到 join()
方法加入的
join
线程执行完为止
static void sleep(long millis)
:
(
指定时间
:
毫秒
)
令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队
抛出
InterruptedException
异常
stop():
强制线程生命期结束,不推荐使用
boolean isAlive()
:
返回
boolean
,判断线程是否还活着
6、线程的调度
(1)调度策略
时间片
抢占式:高优先级的线程抢占CPU
(2)Java的调度方法
同优先级线程组成先进先出队列(先到先服务),使用时间片策略
对高优先级,使用优先调度的抢占策略
7、线程的优先级
(1)线程的优先级等级:
MAX_PRIORITY
:
10
MIN _PRIORITY
:
1
NORM_PRIORITY
:
5
(2)涉及的方法
getPriority()
:
返回线程优先值
setPriority(int newPriority)
:
改变线程的优先级
(3)说明
线程创建时继承父线程的优先级
低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用
8、补充-线程的分类
Java
中的线程分为两类:一种是
守护线程
,一种是
用户线程
。
它们在几乎每个方面都是相同的,唯一的区别是判断
JVM
何时离开。
守护线程是用来服务用户线程的,通过在
start()
方法前调用
thread.setDaemon(true
)
可以把一个用户线程变成一个守护线程。
Java
垃圾回收就是一个典型的守护线程。
若
JVM
中都是守护线程,当前
JVM
将退出。