多线程基础
1.1 进程与线程
什么是进程
.进程是操作系统运行的一个任何(一个应用程序运行在一个进程中)
.进程(process)是一块包含了某些资源的内存区域.操作系统利用进程把它的工作划分为
一些功能单元.
.进程中所包含的一个或多个执行单元称为线程(thread).进程还有用一个私有的虚拟地址空间
仅能被它所包含的线程访问
.线程只能归属于一个进程并且它只能访问该进程所拥有的资源,当操作系统创建一个进程后,
该进程会自动申请一个名为主线程或首要线程的线程.
1.2 什么是线程
一个线程是进程的一个顺序执行流
.同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈,
线程切换时负荷小,因此,线程也被称为轻负荷进程,一个进程中可以包含多个线程.
进程与线程的区别
.一个进程至少有一个线程
线程的划分尺度小于进程,使得多线程程序的并发性高
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大的提高了程序
的运行效率.
.线程在执行过程中与进程的区别在于每个独立的线程有一个程序运行的入口,顺序执行序列
和程序的入口,但是线程不能够独立运行,必须依存在应用程序中,由应用程序提供多个线程
执行控制
.从逻辑角度看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行,但操作系统
并没有将多个线程看做多个独立的应用来实现进程的调度和管理以及分配资源
练习:创建两个线程,分别输出1-1000
使用Thread创建两个线程,分别输出
创建线程
使用Thread创建并启动线程
.Thread类是线程类,其每一个实例表示一个可以引发运行的线程,我可以通过继承该类并
重写run方法来定义一个具体的线程,去中run方法的目的是定义该线程要执行的逻辑
.启动线程时调用线程的start()方法而非直接调用run方法,start方法会将当前线程纳入线程
调度,是当前线程可以开始并发运行,当线程获取时间片段会自动开始执行run方法中的逻辑.
使用RunnAble创建并启动线程
实现RunnAble接口并重写run方法来定义线程体,然后在创建线程的时候将RunnAble的实例
传入并启动线程
这样做的好处在于可以将线程与线程要执行的任务分离开减少耦合,同时java是单继承的,定义
一个类实现runnable接口这样的做法可以更好的实现其他父类或接口,因为接口是多继承关系
练习:
编写一个线程改变窗体的颜色
public class TestRunnAble extends JFrame implements Runnable{
public static void main(String[] args) {
TestRunnAble r = new TestRunnAble();
r.setSize(300,300);
r.setVisible(true);
// 启动线程
Thread t1 = new Thread(r);
t1.start();
}
@Override
public void run() {
int i = 0;
JPanel panel = new JPanel();
panel.setSize(300,300);
this.setContentPane(panel);
while(true) {
i= i==0?1:0;
if(i==0) {
panel.setBackground(Color.yellow);
}else {
panel.setBackground(Color.green);
}
}
}
使用内部类创建线程
.通常我们可以通过内部类的方式创建线程,使用该方式可以简化编写代码的复杂度,当一个
线程仅需要一个实例时我们通过这种方式创建
线程使用的场合
.线程通常用于在一个程序中需要同时完成多个任务的情况,我们可以将每个任务定义为一个
线程,使他们得以一同工作
.也可以用在单一线程中可以完成,但是使用多线程可以更快的情况
并发原理:
.多个线程"同时"运行只是我们感官上的一种表现,事实上线程是并发运行的,OS将时间划分为
很多的时间片段(时间片),尽可能均匀的分配给每一个线程,获取时间片段的线程被CPU运行,
而其他线程全部等待,所有微观上走走停停的,宏观上都在运行,这种现象较并发,但不是绝对
意义上的"同时发生"
线程状态:
1.new 创建线程
2.Runnable 运行状态
3.Running 运行状态
4.Dead run方法执行完毕,等待垃圾回收
特殊状态
休眠状态 sleep()方法 在规定时间内主动让出自己的时间片
阻塞状态 当一个线程试图获取一个内部的对象锁,而该所被其他线程持有,因此进入阻塞状态
等待状态 当一个线程等待另一个线程通知调度器一个条件时,该线程进入等待状态