- 让子类继承Thread线程类
- 子类必须重写Thread类的run方法
- 创建一个自己定义的线程对象
- 调用start()方法启动线程
- 创建一个任务类实现Runnable方法
- 实现Runnable接口的run方法
- 创建一个任务类对象
- 把任务对象交给Thread线程类处理
- 调用线程对象start方法启动线程
扩展
由于每次创建线程都要创建一个实现接口的类,非常麻烦,可以用匿名内部类或Lambda表达式代替
前面几种方法创建的线程均没有返回值,假如线程执行完毕后需要返回,可以用这种方式。
- 定义一个实现Callable接口的类,指定返回数据的类型
- 重写call方法,指定返回类型
- 创建一个Callable对象,注意该对象不是还不是任务对象
- 把Callable类型的对象封装成FutureTask类型的对象
- 把任务对象交给Thread对象
- 获取线程执行完毕后返回的结果
什么是线程安全问题?
答:多线程同时操作同一临界资源,导致结果存在的不准确性。
例题:当两个人同时对同一账号取钱,其其结果导致第一个人把前全部取走,二第二个人还可以继续取钱。
什么是线程同步?
答:线程同步是指一个或多个线程必须等待某个或多个线程执行完某些操作后才能继续往下执行,常用于多线程同时操作同一临界资源问题,但某线程在操作某一临界资源时,其他线程必须等待。
实现线程同步有三种方法:同步代码块、同步方法、lock锁
作用:把访问共享资源的核心代码给上锁,但此线程执行完后会自动解锁,以此保证线程安全。
对之前取钱操作加同步锁
注意:这个锁其实是一个对象,这个对象被引用的时候会被标记,解锁后才会消除标记
所以就有一个问题,如果有小红、小蓝、小黑、小白,四个线程,而业务只需要小红小蓝同步,小黑小白同步,如果锁对象是唯一的,则所有的线程都用同一把锁,则红蓝黑白都会被同步,明明两组不相干的操作却要一起同步等待,就会影响效率,所以要想把两组同步分开,就要加不同的锁,用 this
用this可以识别调用不同对象的线程,但如果要在静态方法里上锁,因为静态方法是直接用类名调用的,不需要创建对象,这时可以用这个类的唯一标识当锁,而这个类的唯一标识是字节码(类名.class)
锁对象的使用规范
- 建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象。
- 对于静态方法建议使用字节码(类名.class)对象作为锁对象。
作用:把访问共享资源的核心方法给上锁,以此保证线程安全。
同步方法底层原理
- 同步方法其实底层也是隐式锁对象的,只是锁的范围是整个方法代码。
- 如果方法是实例方法:同步方法默认用this作为的锁对象。
- 如果方法是静态方法:同步方法默认用类名.class作为锁对象。
- Lock锁是JDK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便。
- Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。
- Lock常用方法
变量类型 方法名称 说明 void lock() 获得锁。 void lockInterruptibly () 除非当前线程是interrupted,否则获取锁定。 Condition newCondition() 返回一个新Condition绑定到该实例Lock实例。 boolean tryLock () 只有在调用时他是空闲的才能获取锁。 boolean tryLock (long time,TimeUnit unit) 如果锁在给定的等待时间内是空闲的并且当前线程不是interrupted,则获取锁。 void unlock () 释放锁定。
什么是线程池?
答:线程池就是一个可以复用线程的技术。
不使用线程池的问题
用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理的,而创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。
谁代表线程池?
答:JDK5.0起提供了代表线程池的接口:ExecutorService。
如何得到线程池对象?
- 方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象,
- 方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象。
- 对于计算机密集型的任务(使用CPU频繁),主机逻辑处理器核数 + 1
- 对于IO密集型的任务,主机逻辑处理器核数 * 2
1、临时线程什么时候创建?
答:新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。
2、什么时候会开始拒绝新任务?
答:核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务。
- 当任务队列未满时不创建临时线程
- 当核心线程在忙且任务队列已满时创建创建临时线程
- 当核心线程和临时线程在满,且任务列表满时,再有任务请求则调用拒绝策略
- 常用策略
- Executors 工具底层都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象。
- 不建议使用这个Executors工具类实现线程池,因为在大型并发系统环境中使用Executors如果不注意可能会出现系统风险。用原始的创建方法可以让开发者更好的理解线程池执行流程,也可以控制线程池一些数据来规避风险。
- 常用方法
Java总共定义了6种状态。
6种状态都定义在Thread类的内部枚举类中
注意得到锁的线程调用 sleep() 进入等待状态,期间不会释放锁,而 wait() 会释放锁。
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/java-jiao-cheng/5469.html