Java多线程_基础
进程和线程
- 进程:
操作系统中一个程序的运行周期叫做一个独立的进程 是操作系统元调度的最小单位 每个进程都拥有一套独立的变量 - 线程:
线程是进程的一个任务
线程之间共享变量
每个线程的内部都有自己的一套变量,每个线程内的变量是私有的(工作内存)(java内存模型)
线程的状态和一些常用方法
-
线程有以下五种状态:
开始、就绪、运行、阻塞 、终止 -
start(): 线程启动
调用这个方法,线程变为就绪态,但是什么时候调用时操作系统决定的
start()方法实际上内部是调用了start0()的本地方法,目的是先进行资源的调度来实现多线程 -
sleep(long time):
线程休眠 ,线程立刻交出CPU给其他线程执行任务,但是不交出锁,等到指定的时间在回复执行,
线程的状态从运行态到阻塞态。
TimeUnit.SECONDS.SLEEP() -
yield()
线程让步,线程交出CPU给其他线程执行任务,但是不立刻交出要等到当前任务完成才会交出
yield()方法只会让有相同优先级的线程有可能获取到CPU
线程从运行态到就绪态,什么时候回到运行态是系统决定的 -
join()
等待线程执行完毕,会阻塞其他线程直到此线程执行完毕
在哪个线程执行该方法就会让哪个线程阻塞
实际上是wait()方法的包装方法 -
currentThread()
获取当前线程 -
getName()
获取线程名称 -
interrupt()
线程中断
不会立刻终止正在运行中的线程,而是等待其运行完毕后才会进行终止
实质:
1.实际上是设置了一个标志位,每当调用interrupt类时,会将标志位改为true
2.如果一个正在阻塞状态的线程(wait(),join(),sleep()),调用了此方法,会立刻终止线程,然后抛出一个InterruptedException(),并将标志位改为false
3.如果先调用iterrupted()方法再,进行阻塞,不会立刻终止线程,等到线程执行完毕后才会抛出InterruptedException()<java高并发编程>
run()方法是线程实现的实体方法 -
线程优先级
线程优先级是优先级高的线程会有可能优先被执行
可以自己设置优先级 方法 setPriority()
优先级是从1到10 主线程的优先级是5 -
守护线程:
是一种守护机制,只要程序中还有工作线程没有结束,守护线程就不会终止,只有最后一个工作线程结束,守护线程才会结束
Java中的守护线程有 垃圾回收线程 -
如何创建多线程
1)通过继承Thread类来实现多线程
2)通过继承Runnable类来实现多线程
实际上,还是需要通过 Thread类中的start()方法来回调Thread类中的run()方法
相当于一种代理模式,核心业务类为自己定义的实现Runnable的类,将类实例化对象传入Thread类里面,来进行多线程的实现
可以使用匿名内部类或者lamda表达式(new Thread(new Runnable{} 或者 new Thread(()->()));
3)通过继承Callable类来实现多线程,和Runnable一样,不过Callable类支持返回提示信息
具体实现
1.Callable不是Thread类的父接口,
2.Callable的返回值是通过一个接口口Future接口的get()方法来获得的
3.Future接口有一个具体子类FutureTask里面有成员变量Callable,
4.FutureTask即是Future的子类又是Runnable的子类,所以可以通过这个类来将核心业务传入Thread类中,来执行多线程的
注意:
Future类保证任务只执行一次,所以看不到多线程,如果想看到多线程就要使用线程池使用submit(Runnable或者Callable)来提交任务
get方法会阻塞当前线程,直到有返回值才会继续向下执行 -
通过线程池来创建多线程
-
什么是线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。 -
线程池创建多线程的好处是什么
1.提高响应速度:每当有一个任务到达,无序创建新线程就可以直接执行
2.减少资源浪费:恢复用已有的线程
3.方便线程的统一管理:对线程进行统一的资源分配调度 -
线程池的几个组成
-
核心线程池:
任务提交后首先在核心线程创建线程 -
工作队列:当核心线程池饱满后将提交的任务放入工作队列等待
1.ArrayBlockingQueue,有界阻塞队列
2.LinkedBlockingQueue,无界阻塞队列
3.SynchroniousQueue,不储存元素的队列
4.PriorityQueue,优先级队列中 -
最大线程池
-
线程活动时间
-
活动时间单位
-
饱和策略
AbortPolicy:当线程池满后直接抛出异常
CallRunsPolicy:调用调用者的线程来执行任务
DiscardOldestPolicy,丢弃队列中最近的一个任务,来执行他
DiscardPolicy,直接丢弃,没有任何提示信息 -
线程池创建多线程的流程
1.任务被提交后,先看核心线程池是否已满,如果不满,直接创建新线程执行任务,如果已满,看当前是否有空闲线程,没有的话执行2
2.将任务存放到工作队列中,在工作队列中排对等待执行,如果工作队列已满执行3
3.将任务提交到最大线程池池中,在里面创建线程执行任务
4.最大线程池已满,执行饱和策略 -
线程的提交
executor(Runnable) 和submit(Runnable /Callable)
-
线程池的关闭
shutdown()
shut() -
Executors创建的几种线程池 Executors为工具方法
newFixedThreadPool
1.核心线程数和最大线程数一样,
2.工作队列是无界队列 使用场景:用于有限的资源下,控制线程个数的场景,适用于负载比较重的任务SingleThreadPoolExecutor
1.单线程池,最大线程池和核心线程池一样,数量为1
2.使用无界队列 使用场景:用于要只能实现一个CachedThreadPool
1.核心线程池为0,最大线程池为MAX_INTERGE
2.工作队列是不能储存元素的队列
3.每次提交任务都会交给创建线程 使用场景:适合负载比较小的轻量级任务, 如果处理任务速度小于提交任务速度,会因为创建多个线程耗尽资源
ScheduledThreadPoolExecutor
定时调度线程池,使用DelayQueue作为工作队列、按周执行任务后有不通的处理
scheduleAtFixedRate(任务,keepAliveTime, TimeUnit.NANOSECONDS)使用此方法来提交线程
scheduleWithFixedDelay