7 多线程
7.1 进程和线程
1、进程
进程是一个正在执行中的程序
每一个进程都有一个执行顺序,该顺序是一个执行路径,或者叫做一个控制单元
2、线程
线程就是进程中的一个独立控制单元
线程在控制着进程的执行
一个进程中至少有一线程
7.2 创建线程的方式
第一种:继承Thread类
步骤:
定义类继承Thread
复写Thread类中的run方法
调用线程的start方法,该方法的作用:启动线程,并调用run方法。
class Demo extends Thread{
public void run(){
System.out.println("demo run");
}
}
class ThreadDemo{
public static void main(String[] args){
Demo d = new Demo();//创建线程
d.start();
}
}
多线程的特点:随机性
多线程运行时,每一次运行的结果都不同。每个线程都在争夺CPU的执行权,谁得到谁就运行。在某一时刻,只能有一个程序运行(多核除外)。CPU在做着快速的切换,以达到同时运行的效果。
run方法用于存储线程要运行的代码
static Thread currentThread():获取当前线程对象
getName():获取线程名称
setName或者构造函数:设置线程名称
第二种:实现Runnable接口
步骤:
定义类实现Runnable接口
覆盖Runnable接口中的run方法
通过Thread类建立线程对象
将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
调用Thread类的start方法开启线程,并调用Runnable接口子类额run方法
实现方式和继承方式的区别
继承Thread:线程代码存放在Thread子类run方法中
实现Runnable:线程代码存放在接口的子类额run方法中
实现方法的好处:避免了单继承额局限性,在定义线程时,建议使用实现方式
class PrimeRun implements Runnable{
public void run(){
System.out.println("demo run");
}
}
class ThreadDemo{
public static void main(String[] args){
PrimeRun p = new PrimeRun();//创建线程
new Thread(p).start();
}
}
7.3 同步
1、同步的前提
必须要有两个或者两个以上的线程
必须是多个线程使用同一个锁
必须保证同步中只有一个线程在运行
2、同步的好处和弊端
好处:解决了多线程额安全问题
弊端:多个线程都需要判断锁,比较消耗资源。
3、同步代码块
synchronized(对象){
需要被同步的代码
}
对象如同锁,持有锁的线程可以在同步中执行。没有持有锁的线程即使获取了CPU的执行权也进不去,因为没有获取锁。
4、同步函数
将synchronized作为函数的修饰符
public synchronized void add(){}
同步函数用的锁:
函数需要被对象调用,那么函数都有一个所属对象引用,就是this,所以同步函数使用的锁是this。
如果同步函数被静态修饰后,使用的锁是Class对象,类名.class。
5、新特性:
jdk1.5之后提供了多线程升级解决方案
将Synchronized替换成实现Lock操作,加锁:lock(),解锁:unlock()
将Object中的wait、notify、notifyall替换成了Condition对象,该对象可通过Lock获取。等待:await(0,唤醒:signal()。
7.4 停止线程
stop方法已经过时。
只有一种方法停止线程:run方法结束。一般都将代码放在循环体中,所以只需要加个标记,控制循环,就可以让run方法结束。
特殊情况:
当线程处于等待状态,就读取不到标记,那么就不会结束。这是就需要使用Interrupt()方法,让等待状态 线程回到活动状态。
7.5 Join和yield
1、Join方法
临时加入线程
加入线程时,当前线程会进入等待状态,直到加入的线程运行完毕,再回到活动状态。
2、yield方法
暂停当前正在执行的线程,并执行其他线程。
7.6 优先级
优先级有1到10,所有线程默认都是5。通常只取1、5和10,为了便于阅读将这三个设为了常量,分别对应MIN_PRIORITY、NORM_PRIORITY、MAX_PRIORITY