今天给大家总结点多线程的知识!内容有点多还是给大家分成几块发出~
多线程
1.什么是进程?什么是线程?
进程是一个应用程序(1个进程是一个软件)
线程是一个进程中的执行场景/执行单元
一个进程可以启动多个线程
2.对于java程序员来说,挡在Dos命令窗口中输入:java HelloWORLD回车之后
会先启动JVM,而JVM就是一个进程
JVM再启动一个主线程调用main方法
同时再启动一个垃圾回收线程负责看护,回收垃圾
最起码,现在的java程序中至少有两个线程并发,一个是垃圾回收线程,一个是执行main方法的主线程
3.进程和线程是什么关系?举个例子
阿里巴巴 :进程
马云:阿里巴巴的一个线程
童文红:阿里巴巴的一个线程
京东:进程
强东:京东的一个线程
妹妹:京东的一个线程
进程可以看作是现实生活当中的公司
线程可以看作是公司当中的某个员工
注意:进程A和进程B的内存独立不共享(阿里巴巴和京东资源不会共享的)
魔兽游戏是一个进程
酷狗音乐是一个进程
这两个进程是独立的,不共享资源
线程A和线程B呢?
在java语言中:线程A和线程B,堆内存和方法区内存共享
但是栈内存独立,一个线程一个栈
假设启动10个线程,会有10个栈空间,每个栈和每个栈之间,互不干扰,各自执行各自的,这就是多线程并发
火车站,可以看作是一个进程
火车站的每一售票窗口都可看作一个线程,所以能提高效率
java中之所以有多线程,就是为了提高程序的处理效率
4.使用了多线程机制之后,main方法结束,是不是有可能程序也不会结束。
main方法结束只是主线程结束了,主栈空了,其他的栈(线程)可能还在压栈弹栈
5.分析一个问题:对于单核的CPU来说,真的可以做到真正的多线程并发吗?
对于多核的CPU电脑来说,真正的多线程并发是没有问题的,
4核CPU表示同一个时间点上,可以真正的有4个线程并发执行
什么是真正的多线程并发?
t1线程执行t1的
t2执行t2的 t1和t2互不影响,这就叫做真正的多线程并发!
单核的CPU表示只有一个大脑:
不能够做到真正的多线程并发,但是可以做到给人一种“多线程并发”的感觉!
对于单核的CPU来说,在某一个时间点上实际上只能处理一件事情,但是由于CPU的处理速度极快,
多个线程之间频繁切换执行,给人的感觉是:多个事情同时在做!!!
线程A:播放音乐
线程B:运行游戏
线程A和线程B频繁切换执行,人类会感觉音乐一直在播放,游戏一直在运行,给我们的韩厥是同时并发的
就像一根针扎到受伤,到最终感觉很疼,这个过程需要很长时间,在这个期间计算机可以进行亿万次循环,所以计算机的执行速度很快
6.java语言中,实现线程有两种方式。
====================================
java支持多线程机制。并且java已经将多线程实现了,我们只需要继承就行了
第一种方式:编写一个类,直接继承java.lang.Thread,重写run方法
public class MyThread extends Thread{
public void run(){}
}
MyThread t=new MyThread()
t.start();
7.创建线程new对象
启动线程调用start()方法
start()方法作用就是:启动一个分支线程,在JVM中开辟一个新的栈空间,完成之后瞬间就结束了
只是为了开启一个新的空间,只要新的栈空间开出来,start()方法就结束了,线程就启动成功了
启动成功的线程会自动调用run方法,并且run方法在分支栈的栈底部(压栈)
run方法在分支栈的栈底部,main方法在主栈的栈底部,run和main是平级的
如果就只有run方法没有start(),是属于单线程,属于方法调用
8.
第二种方式:编写一个类,实现java.lang.Runnable接口,实现run方法
/定义一个可运行的类
public class MyRunnable implements Runnable{
public void run() {}
}
//创建线程对象
Thread t=new Thread(new MyRunnable ());
//启动线程
t.start();
9.总结:第二种方式更好,实现接口比较常用,因为一个类实现了接口,还可以继承其他的类更灵活,第一种不能再继承了
10. Thread t=new Thread(new Runnable() {//接口不能new对象 相当于new 【匿名】 implements Runnable
11.(1)获取线程对象的名字 String name=线程对象.getName();
(2)修改线程对象的名字 线程对象.setName(“线程名字”)
当线程没有设置名字,默认的名字规律:
Thread-0
Thread-1
Thread-2
............
(3)获取当前线程对象
Thread t=Thread.currentThread();
(4)关于线程的sleep方法static void sleep(long millis)
静态方法 Thread.sleep(1000)
参数是毫秒
作用:让线程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其他线程使用
间隔特定的时间,去执行一段特点的代码,每隔多久执行一次
(5)终止线程睡眠 t.interrupt()
sleep睡眠太久了,叫醒!注意:这个不是中断线程的执行 是终止线程睡眠
终止线程的睡眠(这种终端睡眠的方式依靠了java的异常处理机制)
6)强行终止线程的执行t.stop()
这种方式容易丢失数据,直接杀死线程,不建议使用
正确的终止方法:
==========================
package 线程;
//正确的终止线程
public class ThreadTest06 {
public static void main(String[] args) {
Mythread5 m = new Mythread5();
Thread t = new Thread(m);
t.setName("小孩");
t.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
m.run=false;//终止线程
}
}
class Mythread5 implements Runnable {
boolean run=true;
@Override
public void run() {
for (int i=0;i<10;i++) {
if(run==true){
System.out.println(Thread.currentThread().getName() + "--" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else {
//这里可以写要保存的地方东西,终止当前线程
return;
}
}
}
}
12.重点:run()方法当中的异常不能throws,只能try catch
因为run()方法在父类中没有抛出任何异常,子类不能比父类抛出更多的异常
13.(了解)关于线程的调度
常见的线程调度模型
抢占式调度模型:
哪个线程的优先级比较高,抢到的CPU时间片的概率就高一些
均分式调度模型:
平均分配CPU时间篇,每个线程占有的CPU时间片时间长度一样
平均分配,一切平等
有一些编程语言,线程调度模型采用的是这种方式
java中提供了哪些方法是和线程调度有关系呢?
实例方法:
void setPriority(int newPriority)设置线程的优先级
int getPriority()获取线程优先级
最低优先级1
默认优先级5
最高优先级10
优先级比较高的获取CPU时间片可能会多一些(也不一定)
静态方法:
static void yield()让位方法
暂停当前正在执行的线程对象,并执行其他线程
yield()方法不是阻塞方法,让当前线程让位,让给其他线程使用
yield()的执行会让当前线程从“运行状态”回到“就绪状态”
注意:在回到就绪之后,有可能还会再次抢到
实例方法
void join()合并线程(不是合并在一起)
class MyThread1 extends Thread{
public void doSome(){
MyThread2 t=new MyThrea2();
t.join();//当前线程进入阻塞,t线程执行,直到t线程结束,当前线程才可以继续
}
}
class MyThread2 extends Thread{
}