概述
什么是线程
假如我们我们10个集装箱,需要把从A地运往B地,但是我们只有一辆车,就必须一个一个的箱子运过去,,但是如果我们又10个辆车就可以一起运过去。在程序中如果不开通线程,那我们只有1辆车,如果开通了10个线程,我们就拥有了10辆车,一起运过去。效率大大提高。
注意:很多多线程是模拟出来的,真正的多线程是多个cpu,即多核,如服务器。如果模拟出来的多线程,即只有一个cpu的情况下,在同一时间点,cpu智能执行一个代码,因为切换的很快,所以造成了同时执行的假象
本章核心概念
- 线程是独立的执行程序
- 在程序运行的时候,即使自己没有创建线程,后台也会有多个线程在同事执行,如主线程main(),java的垃圾回收机制GC线程等等,
- 一个进程中,如果开了多个线程,线程的运行由调度器安排,调度器与操作系统相关的,线程运行的先后顺序无法人为的干预
- 当同一个资源,多个线程同时操作的时候,特别是对改资源进行增删改的时候,需要加入线程并发机制
线程的创建
- 继承Thread类(不建议使用,单继承有局限性)
//创建线程一:继承Thread类,重写run方法,调用start方法开启线程
public class Thead1 extends Thread{
@Override
public void run() {
System.out.println("这是一个继承Thread类的线程");
}
public static void main(String[] args) {
Thead1 thread1=new Thead1();
thread1.start();
}
}
- 实现Runnable接口
(推荐使用,避免了单继承的局限性,灵活方便,方便同一个对象多个线程使用 )
//创建线程二:实现Runnable接口,重写run方法,创建个Thread 对象,然后将类赋予这个Thread类,然后start
public class Thead2 implements Runnable {
@Override
public void run() {
System.out.println("这是一个继承Thread2类的线程");
}
public static void main(String[] args) {
Thead2 thread_run=new Thead2();
Thread thread=new Thread(thread_run);
thread.start();
}
}
- 实现Callable接口
创建线程:实现Callable<T>接口
class Thead3 implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
System.out.println("这是一个Callable的线程");
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Thead3 thread_run1=new Thead3();
Thead3 thread_run2=new Thead3();
/**
* 创建执行服务
*/
ExecutorService executorService= Executors.newFixedThreadPool(2);
/**
* 提交执行
*/
Future<Boolean> f1= executorService.submit(thread_run1);
Future<Boolean> f2= executorService.submit(thread_run2);
/**
* //获取返回值
*/
Boolean aBoolean = f1.get();
Boolean bBoolean = f2.get();
/**
* 关闭服务
*/
executorService.shutdown();
}
Callable接口的好处:1:有返回值 2、可以抛出异常 3、可以定义同时能够执行的线程个数。如服务的线程数量只有2个,但是提交了3个线程跑,必须等前面的线程跑完后,才会执行第三个线程
线程的五大状态
线程的方法
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 让当前线程休眠millis毫秒(抱着锁睡觉,不会释放锁) |
static void wait(long millis) | 让线程等待(会释放资源) |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的对象,执行其他线程 |
void interrupt() | 中断线程(不推荐使用这个) |
void isAlive() | 测试线程是否处于活跃状态 |
void stop() /destroy() | 停止线程(目前已经处于废弃状态不再使用这个方法了) |
- 线程的停止(不建议使用stop或者destroy方法,建议用一个标志,让线程自动停止)
例如:
class TestThead implements Runnable {
//设置一个标志位
private boolean flag=true;
@Override
public void run() {
while (flag){
System.out.println("这是一个TestThead线程");
}
}
public void stop(){
flag=false;
}
public static void main(String[] args) throws InterruptedException {
TestThead t=new TestThead();
new Thread(t).start();
Thread.sleep(2000);
t.stop();
}
}
- 线程的礼让yield
线程礼让就是让当前的线程暂停,从运行状态变成就绪状态,但是不阻塞,让cpu重新调度,大家一切回到同一起跑线上,当然也有可能cpu还是让礼让的线程先跑也可能,看cpu心情
- 线程join
join 方法就是插队,它就是vip,先执行它,然后其他人再执行
- 线程的优先级
setPriority(int newPriority) 里面的参数就是优先级,优先级最小是1,最大是10.
优先级越高,先执行的概率越大,(注意:不是优先级高的一定先执行
)
线程的同步
当多个线程同时操作一个资源的时候,会出现信息不对称的情况发生,(并发)所以必须解决这个问题,就是线程同步了
- synchronized
每个对象都有一把锁,引入synchronized锁机制,当一个线程获得对象 的排它锁,其他线程无法进入,它一个人独占资源
- synchronized同步方法
(缺陷:如果一个大方法加入synchronized 关键字,会大大的影响效率)
public synchronized void stop(){
}
- synchronized同步代码块
//obj是一个对象,将这个对象锁住,不让其他线程对他进行操作
synchronized(obj){
}