Java并发编程—线程详解


——————————————————————————————

线程简介

什么是线程

进程是由线程组成的
线程本质是一个栈

多线程的使用

什么时候需要使用多线程?

  1. 在cpu产生浪费时,需要性能提升的时候
  • cpu什么时候产生浪费比较严重?
    • 网络IO、磁盘IO的时候浪费比较严重
    • 网络IO:网络请求数据,在数据回来之前cpu一直在打空转
    • 磁盘IO:向磁盘发出调度,等数据回来也是cpu一直在打空转
  1. 需要同时运行多个线程

写多少个线程比较合适?

一般是二十四十个线程比较合适(回答的时候答20~40之间的具体一个数),一方面因为CPU有上下文切换,消耗时间;另一方面读写数据库单批次数据不能太大,太大会影响数据库的性能

线程优先级

下面代码,设置5个高优先级,5个低优先级,让10个线程处于就绪态,一起竞争资源,谁的count越大,谁竞争到的次数越多(优先级高的,竞争到的次数应该高)。
但是结果是,高优先级和低优先级count结果一样,说明设置的优先级没用

public class Priority {
    private static volatile boolean notStart = true;//为true,在29行的循环才能执行
    private static volatile boolean notEnd = true;//为true,在35行的循环才能执行
    public static void main(String[] args) throws Exception {
        List<Job> jobs = new ArrayList<Job>();
        for (int i = 0; i < 10; i++) {
            int priority = i < 5 Thread.MIN_PRIORITY : Thread.MAX_PRIORITY;
            Job job = new Job(priority);
            jobs.add(job);
            Thread thread = new Thread(job, "Thread:" + i);
            thread.setPriority(priority);
            thread.start();
        }
        notStart = false;//10个线程进入就绪态之后,notStart变为true,每个线程进入就绪态后都会进入第二个循环执行++操作
        TimeUnit.SECONDS.sleep(10);//10个线程竞争了10秒钟,在这之前会让jobCount++
        notEnd = false;
        for (Job job : jobs) {
            System.out.println("Job Priority : " + job.priority + ",
            Count : " + job.jobCount);
        }
    }
    static class Job implements Runnable {
        private int priority;//私有的,int类型的优先级
        private long jobCount;//工作次数
        public Job(int priority) {//指定这一次运行的优先级
            this.priority = priority;
        }
        public void run() {
            while (notStart) {//如果notStart为true,一直执行这个循环
            //先进入就绪态的线程,先执行的概率比较大
                 hread.yield();//保证了公平
            //因为进入了运行状态但是没真正执行++操作,只是打空转后让出cpu
            //让出后重新进入就绪态,是操作系统记录位置,不是程序计数器
            }
            while (notEnd) {
                Thread.yield();//这句话是让出cpu的意思
                //为什么要加上这个(因为这个方法不靠谱,并不能立刻让出cpu,cpu会执行一段之间)
                //这个让出cpu后,会执行下面的++操作
                jobCount++;
            }
        }
    }
}

在这里插入图片描述
count数字这么大,也表示Thread.yield();方法不靠谱,并不是执行一次++操作就让出cpu,可能执行了1000次或10000次才让出cpu。

靠谱的让出CPU的方法?

sleep(0)或sleep(1):可以立刻让出cpu

线程的状态

线程的状态有哪几种?

线程状态: 新建状态,就绪状态,运行状态,阻塞状态,等待状态,终止状态(死亡状态)。

  • 新建状态:线程被构建,但是还没有调用start()方法
  • 就绪状态:调用了start()方法,还没开始运行
  • 运行状态:开始运行后,的运行时期
  • 阻塞状态:(是加锁竞争失败的)当几个线程同时竞争资源,竞争失败的线程全部进入阻塞状态,当竞争成功的线程释放锁的时候,会通知进入阻塞状态的线程,他们才会重新进入运行状态竞争资源。(如果是轻量级锁会自旋,能主动能够知道资源被释放了,而重量级锁无法知道资源什么时候释放,需要有人通知他)
  • 等待状态:调用 wait() 或sleep()方法,调用 wait()需要事先加锁
  • 终止状态(死亡状态):线程执行结束,被回收
    在这里插入图片描述

线程的状态转换

在这里插入图片描述

Daemon线程

  • 是一种守护线程,Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。
  • 做辅助性的线程
  • Daemon属性需要在启动线程之前设置,不能在启动线程之后设置

启动和终止线程

通过调用线程的start()方法进行启动,随着run()方法的执行完毕,线
程也随之终止

构造线程

在运行线程之前首先要构造一个线程对象,线程对象在构造的时候需要提供线程所需要
的属性
==》如线程所属的线程组、线程优先级、是否是Daemon线程等信息(设置线程的父线程等)
==》可以通过构造方法加属性,也能通过其他方法加属性。

启动线程

调用start()方法就可以启动这个线程。

  • 启动一个线程前,最好为这个线程设置线程名称,因为这样在使用jstack分析程
    序或者进行问题排查时,就会给开发人员提供一些提示,自定义的线程最好能够起个名字。

理解中断

中断好比其他线程对该线程打了个招呼,其他线程通过调用该线程的interrupt()
方法对其进行中断操作。
如何安全的终止线程

如何安全的终止线程

直接调用interrupt会不会使线程中断?

其他线程想让线程中断,需要在该线程中写代码配合, 如果只单纯的有其他线程调用该线程的中断方法,是不起任何作用的。
线程内需要配合,才能使这个线程中断
在这里插入图片描述
线程通过方法isInterrupted()来进行判断是否
被中断,也可以调用静态方法Thread.interrupted()对当前线程的中断标识位进行复位。

线程间通信

等待/通知机制

一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个
过程开始于一个线程,而最终执行又是另一个线程。
简单的办法是让消费者线程不断地循环检查变量是否符合预期。
在这里插入图片描述
上面这段伪代码在条件不满足时就睡眠一段时间,这样做的目的是防止过快的“无效”尝
试。
1)难以确保及时性。
2)难以降低开销。
在这里插入图片描述
示例:
WaitThread和NotifyThread,前者检查flag值是否为false,如果符合要求,进行后续操作,否则在lock上等待,后者在睡眠了一段时间后对lock进行通知。
(等待状态不会进入竞争,阻塞状态会被唤醒后参与竞争)
在这里插入图片描述

线程应用实例

等待超时模式

前面的章节介绍了等待/通知的经典范式,即加锁、条件循环和处理逻辑3个步骤,而这种
范式无法做到超时等待
假设超时时间段是T,那么可以推断出在当前时间now+T之后就会超时。
定义如下变量:

  • 等待持续时间:REMAINING=T。
  • 超时时间:FUTURE=now+T。
    这时仅需要wait(REMAINING)即可,在wait(REMAINING)返回之后会将执行:
    REMAINING=FUTURE–now。如果REMAINING小于等于0,表示已经超时,直接退出,否则将
    继续执行wait(REMAINING)。
    在这里插入图片描述

CountDownLatch

CountDownLatch属于线程同步的一种,让线程同时执行
CountDownLatch功能:
使用了CountDownLatch来确保ConnectionRunnerThread能够同时开始执行,并
且在全部结束之后,才使main线程从等待状态中返回。

countDownLatch代码

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值