多线程入门
线程和进程
进程
进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间和系统资源
一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。进程是系统进行资源分配和调度的独立单位。
单cpu同一时间点只能执行一件事情,CPU高效的切换让我们觉得是同时进行的
进程就是正在运行的程序 进程是系统进行资源分配和调度的独立单位,每一个进程都有它自己的内存空间和系统资源。
线程
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程
在同一个进程内可以执行多个任务,而这个每个任务就是看成线程 线程,是程序执行的单元,执行路径,是程序使用cpu最基本单位。
cpu 只有一个, 每次只能执行一个(线程)
一个进程有多个线程
单线程 :如果程序只有只有一条执行路径 多线程:如果程序有多条执行路径
并行与并发
并发 逻辑上同时发生,指再某一个时间内同时运行的程序 并行 物理上同时发生,指在某一个时间点同时运行的程序
多线程的意义
并非提高程序的执行效率,其实是为了程序的使用率
程序的执行就是抢占CPU的资源和使用权
当一个进程的线程越多,他能抢到CPU使用权的概率越大
java程序的运行原理
由java命令启动jvm,启动jvm相当于启动了一个进程
接着该进程创建主线程(main)去调用main方法
jvm虚拟机的启动是单线程的还是多线程的?多线程
原因是垃圾回收线程也要启动,不然很容易就内存溢出
Thread的基本使用
创建线程的步骤
-
自定义一个类MyThread 继承Thread类
-
重写run方法
-
创建一个MyThread对象
-
MyThread对象.start()
注: run 与 start 的区别
-
直接调用run方法相同与main线程在调用
-
start() , jvm会创建一个新线程,然后jvm会自动运行线程的run方法
创建对个线程的方法
注:new 多个MyThread对象即可。不是要理解成调用多次start了
MyThread myThread = new MyThread("张三"); //这就是一个线程
MyThread myThread2 = new MyThread("李四");
myThread.start();
myThread2.start();
获得线程的名字
String getName() 返回该线程的名称。
可以在Thread的子类中直接使用
Thread.currentThread() : 得到当前线程对象
System.out.println(Thread.currentThread().getName());
多线程独立栈空间
线程的调度
分时调度:所有线程轮流使用CPU 的使用权,平均分配每个线程占用 CPU 的时间。
抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的是抢占式调度。
设置线程的优先级:
抢占式调度详解:大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序。比如:现在我 们上课一边使用eclipse编辑器,一边使用录屏软件,同时还开着画图板,dos窗口等软件。此时,这些程序是 在同时运行,”感觉这些软件好像在同一时刻运行着“。 实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是 在同一时刻运行。 其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。
线程优化级高,并不能让线程先执行。它还是随机的,只是概率高点
多线程好处:
充分利用CPU的资源(多进程), 多线程(为当前程序抢占CPU使用权)
简化编程模型
带来良好的用户体验
多个线程之间互不干扰
线程的控制
Thread类API
属性:
NORM_PRIORITY : 值为 5
MAX_PRIORITY : 值为 10
MIN_PRIORITY : 值为 1
构造方法:
Thread() :分配一个新的 Thread对象。。
Thread(String name) :分配一个指定名字的新的线程对象。
Thread(Runnable target) :分配一个带有指定目标新的线程对象。
Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。
常用方法:
String getName() :获取当前线程名称。
static Thread currentThread() :返回对当前正在执行的线程对象的引用。
void setName(String name) :将此线程的名称更改为等于参数 name 。
void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
void run() :此线程要执行的任务在此处定义代码。
static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
int getPriority() :返回此线程的优先级。
void setPriority(int newPriority) :更改此线程的优先级。
void join() :等待这个线程死亡。
static void yield() :对调度程序的一个暗示,即当前线程愿意让出当前使用的处理器。
void interrupt() :中断这个线程。
boolean isAlive() :测试这个线程是否活着。
Thread.State getState() :返回此线程的状态。
线程的休眠
public void run() {
// 放让线程执行代码块
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(getName()+"我是最棒的:"+i);
}
}
线程的加入
void join() :等待这个线程死亡。
MyThread myThread = new MyThread("张三"); //这就是一个线程
MyThread myThread2 = new MyThread("李四");
myThread.start();
try {
myThread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
myThread2.start();
线程的礼让
static void yield() :对调度程序的一个暗示,即当前线程愿意让出当前使用的处理器。
public void run() {
// 放让线程执行代码块
for(int i=0;i<10;i++){
Thread.yield(); //让出cpu 使用权
System.out.println(getName()+"我是最棒的:"+i);
}
}
线程的中断
public final void stop (): 让线程停止,过时了,但是还可以使用。
public void interrupt ( )∶中断线程。把线程的状态终止,并抛出一个InterruptedException.
线程的守护
public final void setDaemon(boolean on)
将此线程标记为daemon线程或用户线程。当运行的唯一线程都是守护进程线程时,Java虚拟机将退出。
线程启动前必须调用此方法。
MyThread myThread = new MyThread("张三"); //这就是一个线程
MyThread myThread2 = new MyThread("李四");
myThread.setDaemon(true);
myThread2.setDaemon(true);
myThread.start();
myThread2.start();
// myThread.interrupt();for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"我是最棒的:"+i);
}
Runnable创建多线程
runable方式创建线程
-
创建一个Runable接口的实现类MyRunable
-
重写run方法
-
创建实现类MyRunable对象, myrunable
-
创建Thread类的对象,把 myrunable对象作为构造参数传过去
创建多线程方式总结
实现多线程方式:两种
方法1:Thread类
-
自定义一个MyThread类继承Thread类
-
在MyThread类中重写run方法
-
创建MyThread类的对象
-
启动线程对象。start()方法
方法2:Runable 接口
-
定义一个Runable接口的实现类,MyRunable类
-
在MyRunable类中重写run方法
-
创建MyRunable类的对象myRunable
-
创建Thread类的对象,且将myRunable对象作构造方法的参数传递
-
启动线程 . start方法
问题:为什么有了方法1,还需要方法2
-
为了避免 java 中由于单继承带来的局限性
-
runable接口实现的线程,适合多个相同的代码去处理同一个资源的情况,把线程的同程序的代码,数据进行有效分享,体现了面向对象思想