多线程
一 基本概念:程序,线程 ,进程
1. 程序:
就是指为完成特定任务,用某种语言编写的一组指令的集合,即指一段静态的代码,静态对象
2. 进程:
就是程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程,有他自身的产生,存在和消亡的过程——生命周期
ps:
就好像一首歌在手机中播放的过程就是一个进程运行的过程
- 程序是静态的,进程是动态的
- 进程作为资源分配的单位
3. 线程(多线程可能产生安全隐患)
- 若一个进程在同一时间并发执行一个单位,那么他就叫多线程
- 线程作为调度和执行的单位,每个线程都拥有独立的运行栈和程序计数器。
(就是在同一个进程之中,同时执行不同的步骤的过程,就是多线程的过程)
#特别注意
- 由于一个进程之中自有一个堆和方法区:那么就意味着一个进程里面的多个线程共同拥有一个堆和方法区
- 但是他的运行栈和程序计数器(pc)他是独立的
4. 并行和并发
- 并行: 多个CPU同时执行多个任务,比如:多个人同时做不同的事情。
- 并发: 一个CPU采用时间片的法式执行多个程序:就是多个人去做一件事情
5.多线程的优点
问题提出: 以单核cpu为例,只使用单个线程先后完成多个任务(调用多个方法),绝对会比多个线程来完成用的时间短,为何要使用多线程呢?
- 提高程序的呼应,对图形化界面共有意义,可增加用户的体验
- 提高计算机操作系统dcpu的利用率
- 改善程序结构,将既长且复杂的代码分为多个线程,独立运行,利于理解和修改
何时需要:
-
需要同时执行多个任务
-
程序实现一些需要等待的任务:如用户输入,读写操作,网络操作,搜索等
-
需要一些后台运行的程序时
(就是有多个图片的时候,不断加载图片的时候你就要多线程去加载图片,要不然你会非常的卡顿)
二 线程的创建和使用(重点)
1. Thread类的常用方法:
-
void start(); ——启动进程,并执行对象的run方法
-
run(): ——线程在被调度时执行的操作
-
String getName()——返回线程名称
-
void setName(string name :)——设置线程名字
-
static Thread currentThread()——返回当前线程,在Thread子类中就是this,返回用于主线程和Runnable实现类
-
yield()——其实就是释放当前cpu的执行权,然后就可以交替执行了
-
join()——在B中调用A的join方法,进程B就进入堵塞状态,只有B执行完后,A才可以继续执行 其实就是一个插队命令在线程
-
stop()——强制结束命令(已过时)
-
sleep(lang milltime);——强制堵塞
package demo02; /** 1. void start(); ——启动进程,并执行对象的run方法** 2. **run(): ——线程在被调度时执行的操作** 3. **String getName()——返回线程名称** 4. **void setName(string name :)——设置线程名字** 5. **static Thread currentThread()——返回当前线程,在Thread子类中就是this,返回用于主线程和Runnable实现类** 6.yield方法: */ public class TheadMethodTest { public static void main(String[] args) throws InterruptedException { MyThead a1 = new MyThead("gjh"); MyThead T1 = new MyThead(); // 4. **void setName(string name :)——设置线程名字** T1.setName("线程一"); T1.start(); //方法二:通过有偿构造方法设置 a1.start(); //给主线程命名 Thread.currentThread().setName("主线程"); for (int i = 0; i <100 ; i++) { if (i%20 == 0) { System.out.println(Thread.currentThread().getName()+":"+i); //6.yield()主动释放cpu资源 Thread.currentThread().yield(); } if (i==20){ //分线程T1执行完毕之前不执行 T1.join(); } } } } class MyThead extends Thread{ public MyThead(){ } public MyThead(String name){ super(name); } @Override public void run() { for (int i = 0; i <100 ; i++) { if (i%10 == 0) { try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+i); //this.yield(); } } } }
2.CPU调度策略
- 线程的优先级设置:
- MAX_PRIORITY:10
- MIN_PRIORITY:1
- NORM_PRIORITY:5
-
涉及的方法:
- getPriority() :返回线程优先级
- setPriority(int newPriority) 改变线程的优先级
-
说明
- 线程创建时继承父线程的优先级
- 低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用的
-
如何设置当前线程的优先级
getPriority()–获取当前线程的优先级
setPriority()——设置当前进程的优先级
—优先级高那么他就有可能高概率被先执行
3. 多继承的创建:
方法一:继承与Thread类
-
创建一个继承于thread类的子类
-
重写Thread类的ren()
-
创建Thread类的子类对象
-
通过此对象调用start()
①启动当前进程
②调用当前进程run方法
例子:
package demo01;
/*
* 遍历100以内的偶数
*
*/
//1. 创建一个继承于thread类的子类
class MyThread extends Thread{
/*
2. 重写Thread类的run()方法——>将执行操作写在run里面去
*/
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.print(i+" ");
if (i%20==0){
System.out.println("");
}
}
}
}
}
class ThreadTest {
public static void main(String[] args) {
//3. 创建Thread类的子类对象
MyThread l1 = new MyThread();
//调用他的start方法
l1.start();
//问题一:不可以直接使用run来调用相关进程
//l1.run();
//问题二:一个线程只能调度一次
//l1.run();
//正确做法
MyThread l2 = new MyThread();
l2.start();
//下面的方法依旧实在主线程中执行的
for (int i = 0; i <100 ; i++) {
if (i % 2 == 0) {
System.out.print(i + " -------");
if (i % 20 == 0) {
System.out.println("");
}
}
}
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/1c2dbc341c4dd2da464571cda982fde8.png)
所以可以看出他是多个进程一起执行的
练习:
package demo02;
/**
创建两个分线程
1.遍历一百内的偶数
2.遍历一百以内的奇数
@author 高嘉宏
@date 2021-3-9
*/
public class ThreadDemo {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new