多线程详解
<<线程>>
多线程
1.什么是多线程?
指的是这个程序(一个进程)运行时产生了不止一个线程
.并发:多个线程同时都处在运行中的状态。线程之间相互干扰,存在竞争(抢Cpu)
.并行:多个线程同时执行,但是每个线程各自有自己的CPU,不存在CPU资源的竞争,他们之间也可能存在资源的竞争。
进程: 动态性:程序是静止的,运行中的程序是动态的。
进程就是运行中的程序。
线程(Thread):
Java中线程的代表是:Thread
线程是属于进程的,
线程也是动态性,并发性的。
多个线程就称为多线程。
多线程的程序的效率更高,而且可以解决很多业务问题!
多线程因为是并发抢CPU,所以多线程的执行是“随机的”!
因为多线程的随机性,所以多线程的开发显得比较难理解!
1.主线程和子线程
主线程就是main方法
子线程就是除main方法以外的所有线程
2. 多线程的创建方式:
多线程的创建方式总共有三种:
(1)定义一个类继承Thread然后重写run方法。
优点:代码编写简单
缺点:线程类本身已经继承了Thread所以不能再继承其他类,功能相对较弱。
不适合做线程池。
不能得到线程的运行结果!!
(2)实现一个Runnable接口。
因为线程任务对象只是实现了Runnable接口。所以它可以继续继承其他类
也可以继续实现其他接口,它的功能更强大!
一个Runnable的任务对象可以被多个线程对象使用
很适合做线程池!
缺点:不能得到线程的运行结果!!
(3)实现一个Callable接口。(拓展)
因为线程任务对象只是实现了Callable接口。所以它可以继续继承其他类
也可以继续实现其他接口,它的功能更强大!
一个Callable的任务对象可以被多个线程对象使用
很适合做线程池!
可以得到线程执行的结果!
步骤:1.定义类实现Callable接口
2.创建一个Callable01的线程任务对象:真正执行的代码!
Callable01 call = new Callable01();
3.创建一个未来任务对象:可以在线程执行结束以后获取线程执行的结果!! FutureTask其实是一个Runnable对象
FutureTask<String> task = new FutureTask<>(call);
4.把未来任务对象(其实是一个Runnable对象)包装成线程对象
Thread t = new Thread(task);
5.启动线程 t.start();
多线程执行的特点:
a.多个线程之间会并发抢CPU所以执行也是随机的。
b.启动线程必须使用start方法,不能调用run方法启动线程。
如果直接调用run方法,会变成普通类来执行,从而没有线程特征。
3. 线程的常见API:
线程默认是有名字的。
// 这个代码在哪个线程里面就是得到哪个线程
Thread t = Thread.currentThread();
可以通过t.getName()获取当前线程的默认名称!
可以通过t.setName("线程名称")修改线程的名字!
线程取名字的另一种方式: 通过线程的构造器为线程取名字
步骤:创建一个类继承Thread,调用父类的构造器,把当前线程的名字传上去
4.匿名内部类创建一个Runnable接口的对象
直接new出来
5.线程安全问题:
多个线程在操作同一个资源(共享资源,临界资源)的时候会出现线程安全问题。
解决安全问题的关键:
对于共享资源的访问应该实现先后顺序。
6.线程同步:
就是为了解决线程安全问题。
对于共享资源的访问应该实现先后顺序。
(1)同步方法:
(同步方法底层也是基于同步代码块的,只是同步监视器不需要我们自己指定,
默认是锁当前方法的全部代码)
把出现线程安全问题的方法,给锁起来
每次这个方法只能有一个线程访问,其他线程必须等待!
上锁的格式:在方法上加上一个关键字synchronized,这样方法就同步了。
* 如果默认锁的方法是实例方法,那么默认的同步监视器:是this
* 如果默认锁的方法是静态方法
那么默认的同步监视器是:当前 类名.class
7.同步代码块
把出现线程安全问题的代码(临界区),
锁起来,这样就只能一个线程先访问完成其他线程才可以进来继续访问。
格式:
// 同步监视器就是锁的意思。
// 原则任意唯一对象都可以作为同步监视器。
// 但是建议用共享资源(当前账户)作为同步监视器。
// 因为通常大家都是用共享资源作为同步监视器。
synchronized(同步监视器){
// 被锁的代码块
}
8.显示锁!
private final ReentrantLock lock = new ReentrantLock();
lock.lock(); 上锁
lock.unlock(); 解锁
9.线程的控制
用法:创建对象后都能点出来
.线程休眠:
Thread.sleep(休眠的时间毫秒);
9.能够说出线程6个状态的名称
新建 就绪 运行 死亡 阻塞 死锁!