多线程
1.1 进程 线程 程序
程序: 是为了完成特定任务 用某种语言编写的一组指令的集合。指的一段静态。
进程:是程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程:有他自身的产生 存在 以及消亡的过程–生命周期
程序是静态的 进程是动态的。进程作为资源分配单位,系统在运行时会为每个进程分配不同的内存区域。
线程(thread) 进程进一步细化就是线程,是一个程序内部的一条执行路径。
若一个进程同一时间并行执行多个线程,就是支持多线程。
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器,线程的切换开销比较小。
一个进程中的多个线程共享相同的内存单元和内存地址空间,他们从一个堆中分配对象,可以访问相同的变量和对象。这就是的线程间的通信变得简便和高效。但多个线程操作共享的系统资源可能会带来安全隐患。
单核CPU和多核CPU
在java中 一个程序至少有三个线程组成, 主线程(main) 垃圾回收线程(gc) 异常处理线程。
并行和并发:
- 并行:多个CPU同时执行多个任务
- 并发: 一个CPU在同一时刻,同时处理多个任务。
使用多线程的优点:
1 提高了应用程序的响应。
2 提高了计算机CPU的利用率
3 改善程序结构。
何时需要多线程?
- 程序需要同时执行两个或多个任务
- 程序需要实现一些需要等待的任务的时候:如:用户输入,文件读写 网络操作等。
- 需要一些后台运行的程序时
1.2 实现多线程
创建一个新的执行线程有两种方法。
- 一个是将一个类声明为
Thread
的子类。 这个子类应该重写Thread的run方法 。 然后可以分配并启动子类的实例 - 另一种方法来创建一个线程是声明实现类
Runnable
接口。 那个类然后实现了run
方法。 然后可以分配类的实例,在创建Thread
时作为参数传递,并启动
1.2.1 实现线程的方式一: 继承Thread类
//自定义了一个线程类
public class MyThread extends Thread{
@Override
public void run() {
for(int i = 0 ; i < 100 ;i++){
System.out.println(i);
}
}
}
public static void main(String[] args) {
// 创建了两个线程
Thread t1 = new MyThread();
Thread t2 = new MyThread();
// t1.run();//调用线程的run方法 不属于多线程
// t2.run();
// start() 导致此线程开始执行; Java虚拟机调用此线程的run方法。
t1.start();//启动线程
t2.start();
}
为什么要重写run方法?
因为run方法是用来封装被线程执行的代码的。
run方和start方法的区别、?
run()封装了线程执行的代码,直接调用的,相当于普通方法调用。
start方法 启动线程,然后由jvm调用此线程的run方法
Thread t3 = new Thread(){
@Override
public void run() {
System.out.println("创建线程 ");
}
};
1.2.2 实现线程的方式二: 实现Runnable接口
-
public interface Runnable
Runnable
接口应由任何类实现,其实例将由线程执行。 该类必须定义一个无参数的方法,称为run
public class MyRannable implements Runnable{
@Override
public void run() {
for (int i= 0 ; i < 1000 ; i ++){
System.out.println(i);
}
}
}
public class MyRunnableTest {
public static void main(String[] args) {
Runnable r = new MyRannable();
Thread t1 = new Thread(r);//线程负责执行Runnable接口的方法
Thread t2 = new Thread(r);
//启动线程
t1.start();
t2.start();
}
}
另一种写法:
//Thread t3 = new Thread(new Runnable() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程创建");
}
}).start();
//t3.start()
1.3 设置和获取线程的名称
-
Thread(String name)
分配一个新的Thread
对象。 -
|
void
|setName(String name)
将此线程的名称更改为等于参数name
。 |
| ------ | ------------------------------------------------------------ | -
void
setName(String name)
将此线程的名称更改为等于参数name
。 -
static Thread
currentThread()
返回对当前正在执行的线程对象的引用。
public class MyRunnableTest {
public static void main(String[] args) {
Runnable r = new MyRannable();
Thread t1 = new Thread(r,"线程001");//线程负责执行Runnable接口的方法
Thread t2 = new Thread(r);
t2.setName("线程002");
//Thread t3 = new Thread(new Runnable() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程创建");
}
},"线程003").start();//设置线程名称
//t3.start();
//启动线程
t1.start();
t2.start();
System.out.println(Thread.currentThread().getName());//获取系统当前正在执行的线程
}
}
public class MyRannable implements Runnable{
@Override
public void run() {
for (int i= 0 ; i < 1000 ; i ++){
System.out.println(Thread.currentThread().getName()+"------------->"+i);
}
}
}
1.4 线程的优先级
-
int
getPriority()
返回此线程的优先级。 -
void
setPriority(int newPriority)
更改此线程的优先级。 -
每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行
线程的两种调度模型
分时调度: 所有线程轮流实现CPU的使用权,平均分配每个线程占有CPU的时间片
抢占式调度: 优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个。优先级高的线程获得CPU执行权的概率更高。
java是的是抢占式的调度模型。
线程的默认优先级为5,线程的优先级的范围为1–10
public static void main(String[] args) {
Runnable r = new MyRannable();
Thread t1 = new Thread(r,"线程001");//线程负责执行Runnable接口的方法
Thread t2 = new Thread(r);
t2.setName("线程002");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
for (int i= 0 ; i < 1000 ; i ++){
System.out.println(Thread.currentThread().getName()+"------------->"+i);
}
}
});
t3.setName("线程003");
// 设置线程的优先级
t1.setPriority(5);
t2.setPriority(10);
t3.setPriority(1);
t3.start();
//启动线程
t1.start();
t2.start();
}
System.out.println(Thread.MAX_PRIORITY);//线程最大优先级 10
System.out.println(Thread.MIN_PRIORITY);//最小优先级 1
System.out.println(Thread.NORM_PRIORITY);//默认优先级为5