1.什么线程?
首先要知道什么是进程:
进程是系统分配资源和调度的基本单位,是计算机中的程序关于某数据集合上的一次运行活动, 也就是说进程可以单独运行一段程序。进程是线程的容器。
线程:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是
进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
多线程是为了充分利用cpu资源。提高效率。
2.如何在java中使用多线程?
分为三种方法:
1.继承Thread类 2.实现Runnable接口 3.实现Callable接口
2.1继承Thread类创建
重写run方法 ,当线程启动时会调用run方法的内容
2.2实现Runnable接口创建
实现接口需要创建一个新对象接收
2.3实现Callable接口
这个创建方法过于麻烦,后面会使用线程池来执行任务。
尽量不要自己创建线程对象,而是使用线程池中的对象
2.4常用方法
获取和设置线程名
Thread线程类中常用的方法
休眠:public static void sleep(long millis)
当前线程主动休眠millis毫秒。
放弃:public static void yield()
当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片
加入:public final void join()
允许其他线程加入到当前线程中,直到其他线程执行完毕后,当前线程才会执行。
优先级:线程对象.setPriority()
线程优先级1-10,默认为5,优先级越高,表示获取CPU的概率越高。
守护线程:线程对象.setDaemon(true);
设置为守护线程。线程有两类:用户线程(前台线程)和守护线程(后台线程)如果程序中所有前台线程都执行完毕了,后台线程也会自动结束。垃圾回收线程属于守护线程。
3.线程安全
当多个线程共享一个资源时,可能会出现线程安全问题
前面的代码中就出现了,重复卖一张,甚至会多卖,一个线程读取了另一个线程未修改的数据。
想要解决那就要用到锁,凡是用锁 锁定的代码都是原子操作。
第一种:自动锁 synchronized(共享对象)
第二种:手动锁
.lock上锁 .unlock开锁
4.什么是死锁
两个或多个进程或线程在互相等待对方的资源而无法继续执行的状态。
每个进程或线程都持有一个资源并等待其他进程或线程释放所需要的资源。
如果所有的进程或线程都无法继续执行,则系统就会陷入死锁状态。
Y跟L都需要对方施放锁才能继续进行,导致他们一直在等待陷入死锁状态
如何解决死锁:
(1) 减少同步代码块的嵌套。
(2)设置锁的超时时间。
(3)可以使用安全类-jdk提高的安全类。
5.线程通信
多个线程在并发执行的时候,他们在CPU中是随机切换执行的,这个时候我们想多个线程一起来完成一件任务,这个时候我们就需要线程之间的通信了,准备处理数据的线程等待数据变为可用。换句话说,它在等待另外一个线程的信号
Java有一个内建的等待机制来允许线程在等待信号的时候变为非运行状态。java.lang.Object 类定义了三个方法,wait()、notify()和notifyAll()来实现这个等待机制。
等待:
public final void wait() 释放锁,进入等待队列。
public final void wait(long timeout) 能够设置等待时间,时间到了自动唤醒
通知:
public final void notify() 随机唤醒一个等待队列中的线程;
public final void notifyAll() 唤醒全部进入就绪状态;
关于线程的状态
线程的状态是指线程在执行过程中所处的不同状态,常见的线程状态有以下几种:
1. 新建(NEW):线程被创建但还未启动。
2. 就绪:线程被创建并已经准备好执行,等待系统进行调度。
3. 运行:线程正在执行任务。与就绪状态并为 (RUNNABLE)
4. 阻塞(BLOCKED):线程在等待某个条件满足时暂停执行。
5. 等待(WAITING):线程在等待某个对象的状态发生变化时暂停执行。
6. 超时等待(TIMED_WAITING):线程在等待某个对象状态发生变化时,设置了等待超时时间,在超时时间内未能满足条件,则继续执行。
7. 终止(TERMINATED):线程执行结束或被强制中断。
不同的线程状态可以通过调用线程对象的getState() 方法获取。
6.线程池
频繁的创建及销毁线程会增加虚拟机回收频率、资源开销,造成程序性能下降。
线程池原理:创建一定量公共线程,执行任务时调用池中线程,任务完成后还回到池中,而不销毁
6.1线程池的创建:
1.固定线程池
ExecutorService executorService = Executors.newFixedThreadPool(线程数量);
指定线程数,没有空闲线程时进行等待
2.单一线程池
ExecutorService executorService = Executors.newSingleThreadExecutor()
里面只有一个线程
3.可变线程池
ExecutorService executorService = Executors.newCachedThreadPool();
当前线程忙不过来时就添加线程
4.延迟线程池
设置时间过多久后开启线程
注:上面通过Executors工具类创建线程池,但是阿里巴巴不建议使用。阿里建议使用原生的模式创建线程池。
5.原生模式创建
原生模式需要的参数:
int corePoolSize,核心线程的个数
int maximumPoolSize,最多的线程个数
long keepAliveTime, 线程空闲时间。
TimeUnit unit, 空闲时间的单位
BlockingQueue<Runnable> workQueue:等待队列
6.2常用方法
Executor: 它是线程池的根接口:
void execute(Runnable command):执行Runnable类型的任务。
ExecutorService: 它是Executor的子接口。
void shutdown():关闭线程池。需要等任务执行完毕。
shutdownNow(); 立即关闭线程池。 不在接受新的任务。
isShutdown(): 判断是否执行了关闭。
isTerminated(): 判断线程池是否终止。线程池中的任务都执行完毕,并且线程池关闭了
submit(Callable<T> task);提交任务,可以提交Callable
submit(Runnable task): 提交任务,可以提交Runnable任务
Executors: 它是线程池的工具类,该类提供了创建线程池的一些静态方法