进程
- 是指一个内存运行的应用程序,每一个进程都有一个独立的内存空间
- 一个进程启动后,里面若干的执行路径可划分为若干线程
线程
- 在进程的基础上进行划分的是它的一个执行路径,共享一个内存空间
- 线程之间可以自由切换,并发执行
- 一个进程最少有一个线程
线程调度
- 分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。
- 抢占式调度:
- 优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随性机),Java使用的为抱占式调度。
- CPU使用抢占式调度模式在多个线程间进行着高遇的切换,对于CPU的一个核新而言,某个时刻,只能执行一个线程,而CPUB9在多个线程间切资速度相对我们的觉要快,看上去就是在同一时刻运行,其实,多线是程序井不能提高程序的运行速度,但能够提高程序进行效,让CPU的使用率更高
同步与异步
- 同步:排队执行,效率低但是安全
- 异步:同时执行,效率高但不安全
并发与并行
- 并发:两个或多个事件在同一时间段内发生
- 并行:两个或多个事件在同一时间刻发生
在Java中实现多线程技术
- Thread类:提供的用于实现线程的类
public class myThread extends Thread{
/**
*run 方法就是线程要执行的任务方法
*/
public void run(){
//这里代码就是一条路径
//这个执行路径的处罚方式,不是调用run方放,而是通过Thread对象的start()来启动任务
for(int i=0;i<10;i++){
System.out.ptintln("我爱学习"+i);
}
}
}
//重新创建一个类
public class Try{
public static void main(String[] args){
//Thread
myThread m = new myThread();
m.start();
for(int i=0;i<10;i++){
System.out.ptintln("学习爱我"+i);
}
}
}
//分配时抢占式分配 两个线程 每次执行结果都可能不一样
- 实现Runnable接口
- 优势:
- 通过创建线程任务再分配的方式来实现,更适合多个线程同时执行相同任务情况
- 可避免单线程带来的局限
- 任务与线程时分离的,提高程序健壮性
- 后续学习的线程池技术,接受该类型任务,不接受Thread类线程
public class myRunnable implements Runnable{
@Override
public void run(){
//线程的任务
for(int i=0;i<10;i++){
System.out.ptintln("我爱学习"+i);
}
}
}
//这个类写好之后就相当于有了一个给线程执行的任务
//实现该任务还得借助于Thread
public static void main(String[] args){
//实现Runnaale
//1.创建一个任务对象
myRunnable r = new Runnaale();
//2.创建一个线程,为其分配任务
myThread m = new myThread(r);
m.start();
for(int i=0;i<10;i++){
System.out.ptintln("学习爱我"+i);
}
}
设置和获取线程名称
System.out.println(Thread.currentThread().getName ());
//Thread.currentThread() 获取当前正在执行的线程对象
//得到的类型是Thread
线程休眠sleep
for(int i=0;i<10;i++){
System.out.ptintln(i);
Thread.sleep(millis:1000);
//里面能添毫秒/毫秒加纳秒
//millis:1000 一千毫米==一秒
}
线程阻塞
- 所有比较消耗时间的操作
线程的中断
- 一个线程是一个独立的执行路径,它是否应该结束应有自身决定
- 通过打入中断标记来进行,线程在特殊情况时会去查看标记并抛出异常
- 早期有stop这个方法来从外部掐掉线程,弊端是线程后续操作无法执行
public class Try{
public static void main(String[] args){
Thread t1 =new Thread( new myRunnable());
t1.start();
for(int i=0;i<10;i++){
System.out.ptintln(Thread.currentThread().getName ()+":"+i);
try{
Thread.sleep(millis:1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
//给线程t1设置中断标记
t1.interrupt();
}
}
public class myRunnable implements Runnable{
@Override
public void run(){
for(int i=0;i<10;i++){
System.out.ptintln(Thread.currentThread().getName ()+":"+i);
//因为父类没有抛出异常 所以子类无法使用超出父类的操作
try{
Thread.sleep(millis:1000);
}catch(InterruptedException e){
//e.printStackTrace();
//1.发现中断标记了 选择让其自杀
System.out.ptintln("发现了中断标记让其自杀");
return;
//2.也可以发现了中断但是不做处理
System.out.ptintln("发现了中断标记不做处理");
}
}
}
}
守护线程
- 线程分为守护线程和用户线程
- 用户线程:当一个进程不包含任何的存活用户线程时,进行结束
- 守护线程:当最后一个用户线程结束时,所有守护线程都自动死亡
Thread t1 =new Thread( new myRunnable());
//设置成守护线程
t1.setDaemon(true);
t1.start();
保证线程安全
隐式锁
- 同步代码块
- 格式:synchronized(锁对象){} 锁对象必须是同一把锁 {}里是被执行的操作
- 同步方法
static class Ticket implements Runnable{
//票数
private int cpunt = 10;
public void run(){
while(true){
booleanb flag = sale();
if(!flag){
break;
}
}
}
}
public synchronized boolean sale(){
if(count>0){
//卖票
System.out.ptintln("准备卖票");
try{
Thread.sleep(millis:1000);
}catch(InterruptedException e){
e.printStackTrace();
}
count--;
System.out.ptintln(Thread.currentThread().getName ()+"出票成功,余票:"+count);
return true;
}else{
//break;
return false
}
}
显式锁Lock
static class Ticket implements Runnable{
//票数
private int cpunt = 10;
//显式锁
Look lock = new Rentrant();
public void run(){
while(true){
lock.lock();
if(count>0){
//卖票
System.out.ptintln("准备卖票");
try{
Thread.sleep(millis:1000);
}catch(InterruptedException e){
e.printStackTrace();
}
count--;
System.out.ptintln(Thread.currentThread().getName ()+"出票成功,余票:"+count);
}else{
//break;
break;
}
lock.unLock();
}
}
线程的六种状态
- new 尚未启动的线程处于此状态
- runnable 在Java虚拟机中执行的线程
- blocked 被阻塞等待监视器锁定的线程
- waiting 无限期等待另一个线程执行特定操作的线程
- timewaiting 正在等待另一个线程执行最多指定等待时间的操作的线程
- terminated 已退出的线程
Callbale
runnable与callbale
接口定义
//callbale接口
public interface Callable<v>{
v call() throws Exception;
}
//runnable接口
public interfac runnable{
public abstract void run();
}
callbale使用步骤
1. 编写类实现callbale接口 实现call()方法
class xxx implements callbale<>{
public<T> call() throws Exception{
return T;
}
}
2. 创建FutureTask对象 并传入第一步编写的callbale类对象
FutureTask<Integer> future = new FutureTask<>(callable);
3. 通过Thread 启动线程
new Thread(future).start();
//使用例子
public static void main(String[] args){
Callbale<Integer> c = new myCallbale();
FutureTask<Integer> task = new FutureTask<>(c);
task.isDone();//判断线程是否执行完毕
task.cancel();//取消线程()里是布尔类型的
new Thread(task).start();
Integer j = task.get();
System.out.ptintln("返回值为:"+J);
forint i=0;i<10;i++){
try{
Thread.sleep(millis:100);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.ptintln(i);
}
}
static class myCallable implements Callable<Integer>{
public Integer call() throws Exception{
//Thread.sleep(3000);
forint i=0;i<10;i++){
try{
Thread.sleep(millis:100);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.ptintln(i);
}
}
}
runnable与callbale的相同点
- 都是接口
- 都可以编写多线程程序
- 都采用Thread.start()启动线程
线程池 Executors
- 如果并发执行的线程较多,每个线程执行任务的时间也很短,那么频繁创建线程、销毁线程会大大降低系统的效率
- 线程池是一个容纳多个线程的容器,池中线程可以反复使用
好处 - 降低资源消耗、提高反应速度、提高线程可管理性
java中四种线程池 ExecutorService
- 缓存线程池
- 判断池中是否有空闲线程有就使用,没有的话创建线程放入缓存池中再使用
public class Demo1 {
/**
*缓存线程池
*(长度无限制)
* 任务加入后的执行流程:
* 1.判断线程池是否存在空闲线程
* 2.存在则使用
* 3.不存在,则创建线程并放入线程池,然后使用
*/
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
//指挥线程池执行新的任务
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"我爱学习");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"我爱学习");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"我爱学习");
}
});
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
- 定长线程池
- 判断是否有空闲,没有且线程池未满的情况下创建再使用,若池满则等待空闲
public class Demo2 {
/**
* 定长线程池.
* (长度是指定的数值)
* 任务加入后的执行流程:
* 1.判断线程池是否存在空闲线程2.存在则使用
* 3.不存在空闲线程,且线程池未满的情况下,则创建线程并放入线程池,然后使用
* 4.不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
*/
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(2);
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"我爱学习");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"我爱学习");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"我爱学习");
}
});
}
}
- 单线程线程池
- 空闲用不空闲等待
public class Demo3 {
/**
* 单线程线程池.
* 执行流程:
* 1.判断线程池的那个线程是否空闲
* 2.空闲则使用
* 3.不空闲,则等待池中的单个线程空闲后使用
*/
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
//多执行几个线程 看是不是只出来一个线程名称
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"我爱学习");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"我爱学习");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"我爱学习");
}
});
}
}
- 周期性任务定长线程池
- 可定时间隔时长周期重复执行
public class Demo4 {
/**
* 周期任务定长线程池.
* 执行流程:
* 1.判断线程池是否存在空闲线程
* 2.存在则使用
* 3.不存在空闲线程,且线程池未满的情况下,则创建线程并放入线程池,然后使用
* 4.不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
*
* 周期性任务执行时:
* 定时执行,当某个时机触发时,自动执行某任务﹒
*/
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
/**
* 1.定时执行一次
* 参数1.定时执行的任务
* 参数2.时长数字
* 参数3.时长数字的时间单位,TimeUnit的常量指定
service.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"我爱学习");
}
},5, TimeUnit.SECONDS);//五秒钟后执行*/
/**
* 周期性执行任务
* 参数1.任务
* 参数2.延迟时长数字〔第一次执行在什么时间以后)
* 参数3.周期时长数字〔每隔多久执行一次)
* 参数4.时长数字的单位
*/
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"学习爱我");
}
},5,1,TimeUnit.SECONDS);//五秒钟后执行第一次,再每间隔一秒执行一次
}
}
lambda表达式
函数式编程思想
面向对象:创建对象调用方法解决问题.
public class Lambda {
public static void main(String[] args) {
//冗余的Runnable代码
/*
Thread t = new Thread(new Runnable( ){
@Override
public void run() {
System.out.println("我爱学习");
}
});
t.start();*/
Thread t = new Thread((/*参数*/)->{
System.out.println("我爱学习");
//这个大括号里可以写多个内容用;隔开
});
t.start();
}
}
public class Lambda2 {
public static void main(String[] args) {
//修改前
print(new MyMath() {
@Override
public int sum(int x, int y) {
return x+y;
}
},100,200);
//修改后 保留方法参数部分和方法体
print((int x, int y) ->{
return x+y;
},100,200);
}
public static void print(MyMath m,int x, int y){
int num = m.sum(x, y);
System.out.println(num);
}
static interface MyMath{
int sum(int x,int y);
}
}