Java多线程总结笔记

目录
线程概述
线程创建方式及示例
线程的状态
线程中断
线程安全和不安全问题
线程间的通讯
线程池

一、概述

1、什么是线程?
线程是操作系统能够进行运算调度的最小单位,它是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行。一个进程最少有一个线程。
2、线程和进程的区别
进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间。
1)线程是进程的子集,一个进程可以有很多线程,每条线程并发执行不用的任务。
2)不同的进程使用不用的内存空间,所有的线程共享一片相同的内存空间。
–并发和并行
并发:指两个或多个事件在同一个时间段内发生。
并行:指两个或多个事件在同一时刻发生(同时发生)。
3、为什么要使用多线程?
1)发挥多核CPU的优势
A-目前笔记本、服务器等至少都双核,甚至4核、8核等,若是单线程的程序,在双核CPU上就会浪费掉50%,其他的不言而喻。
B-而实际上CPU使用抢占式调度模式在多个线程间进行着高速的切换。对单核CPU而言,某个时刻,只能执行一个线程,只是看上去就是在同一时刻运行。
C-多核CPU的多线程能让多段逻辑同时工作,真正发挥多核CPU的优势,达到充分利用CPU的目的。
2)防止阻塞
首先需要明确多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU使用率更高。对单核CPU使用单线程,要这个线程阻塞,那么程序将会停止运行,影响任务执行。
3)便于建模
对于大型任务而言,分解任务来考虑程序模型,并使用多线程分别运行程序,提高效率。

二、线程创建方式

方式一:继承Thread类

//继承Thread类
public class Demo1 {
    public static void main(String[] args) {
        //MyThread类实例化
        MyThread m = new MyThread();
        m.start();
        for(int i = 0;i<10;i++){
            System.out.println("汗滴禾下土"+i);
        }
    }
}
public class MyThread extends Thread{
    /**
     * run()方法就是线程要执行的任务方法
     * 重写run方法
     */
    @Override
    public void run() {
        //这里的代码就是一条新的执行路径
        //执行路径的触发方式,不是调用run,而是通过thread对象的start()来启动任务
        for(int i = 0;i<10;i++){
            System.out.println("锄禾日当午"+i);
        }
    }
}

运行结果:
在这里插入图片描述
方式二:实现Runnable接口

//方法2:实现Runnable接口
public class Demo2 {
    public static void main(String[] args) {
        //1、创建一个任务(MyRunnable)对象
        MyRunnable r = new MyRunnable();
        //2、创建一个线程,并为其分配一个任务
        Thread t = new Thread(r);
        //3、执行线程
        t.start();
        for(int i = 0;i<10;i++){
            System.out.println("疑是地上霜"+i);
        }
    }
}
/**
 * 用于给线程执行的任务
 */
public class MyRunnable implements Runnable{
    public void run(){
        //线程的任务
        for(int i = 0;i<10;i++){
            System.out.println("床前明月光"+i);
        }
    }
}

运行结果:
在这里插入图片描述
方式三、实现Callable接口
步骤:
1.创建Callable的实现类,重写call()方法,该方法为线程执行体,并且该方法有返回值。
2.创建Callable的实例,并用FutureTask类来包装Callable对象,该FutureTask封装了Callable对象call()方法的返回值
3.实例化FutureTask类,参数为FutureTask接口实现类的对象来启动线程
4.通过FutureTask类的对象的get()方法来获取线程结束后的返回值
Demo:
在这里插入图片描述
三种方式的对比:
1、采用实现Runnable、Callable接口的方式创建多线程
优势:不局限于单继承。多个线程共享一个对象,处理同一份资源,从而将CPU、代码和数据分开,也体现了java面向对象的思想。
劣势:想要访问当前线程,必须使用Thread.currentThread()方法。
2、使用继承Thread类
优势:编写简单,访问当前线程,直接使用this即可。
劣势:只能是单继承。
3、Runnable和Callable的区别
1)Runnable重写的方法是run(),返回值为void,而Callable是call()方法,返回值类型为泛型。。
2)run方法不能抛出异常,而call可以。
3)Callable+Future/FutureTask可以获取多线程运行的结果,通过Future对象可以了解任务执行情况,可取消任务的执行。

三、线程的状态

1、新建状态(new):当线程对象对创建后,即进入了新建状态
2、就绪状态(Runnable):调用start()即可进入就绪状态,此线程是做好准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行。
3、运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。
4、阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

四、线程中断

问题:
Thread的stop方法已被弃用,调用方法时,会出现下边情况:
1、即刻抛出ThreadDeath异常,在线程的run()方法内,任何一点都有可能抛出异常,包括在catch或finally语句中。
2、会释放该线程所持有的所有的锁,而这种释放是不可控制的,非预期的。
查看Thread源码可以发现,Thread.stop()方法是同步的 ,而工作线程的run()方法也是同步。会导致主线程和工作线程共同争用同一个锁(工作线程对象本身) , 由于工作线程在启动后就先获得了锁,所以无论如何,当主线程在调用stop()时,它必须要等到工作线程的run()方法执行结束后才能进行,导致上述现象。
->使用sleep休眠线程
1、sleep(long millis):让当前线程休眠XXX毫秒
2、join(long millis, int nanos):让当前线程休眠millis毫秒+nanos纳秒

五、线程安全问题

当多个线程访问共享资源时,因为线程调度不确定性,导致该资源最后的属性状态不一致的问题,就称为线程安全问题。
首先通过一个线程不安全的例子来说明:
在这里插入图片描述
结果:
在这里插入图片描述
当3个线程同时使用一个变量count时,最后出现不合逻辑的情况,即为线程不安全。
解决方案一:同步代码块
格式:synchronized(锁对象){}
在这里插入图片描述
结论:3个线程看同一把锁
在这里插入图片描述
解决方案二:同步方法,即将方案一中的if抽成方法,给方法加关键字synchronized
在这里插入图片描述
解决方案三:显式锁Lock
在这里插入图片描述

六、线程间的通讯

在实际开发时,往往会碰到多线程模型,可能某个线程需要拿到另一个线程的计算数据,但是因为线程调度的不确定性,所以需要通过线程间通讯的技术实现线程之间的数据交换。
线程间通讯的方法:
1、wait()/ notify()方法
2、阻塞队列

七、线程池Executors

1、为什么使用线程池?
当并发的线程数量很多时,每个线程都执行一个很短时间的任务就结束了,这样频繁创建线程就会大大降低 系统的效率。线程池是一个容纳多个线程的容器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。
2、线程池的优点
1)降低资源消耗
2)提高相应速度
3)提高线程的可管理性。
3、java中的四种线程池
1)缓存线程池
->判断线程池是否存在空闲线程
->存在则使用
->不存在,则创建线程,并放入线程池使用。

ExecutorService service = Executors.newCachedThreadPool();

2)定长线程池
newFixedThreadPool,可控制线程最大并发数,超出的线程会在队列中等待。
3)单线程线程池
newSingleThreadExecutor,只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。
4)周期性任务定长线程池
newScheduledThreadPool ,支持定时及周期性任务执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值