java程序中会默认存在的三个线程
- main方法:主线程
- GC(垃圾回收机制,回收不用的垃圾内容数据)
- 异常处理机制
线程的创建和使用
创建线程的方式
- 继承Thread类
- 实现Runable接口
- 实现CallBack接口
- 线程池
Thread类
继承Thread类,那么Talk1这个类就是一个线程类
1 | public class Talk1 extends Thread { |
1 | // 怎么使用线程? |
Runnable接口
1 | // 1.定义类实现Runnable接口 |
Callable接口
Callable里面有个call方法,该方法是有返回值的,也就代表线程执行完后会有返回值
需要借助FutureTask类,可以获取返回值
- 创建类型实现Callable接口,并指定返回值类型
- 重写call方法,线程最终调用的方法,类似run方法
- 创建callable的实现类对象
- 创建FutureTask对象,同时指定泛型,与接口一致
- 创建线程对象,将FutureTask对象传入,启动线程
1 | public class Test06 implements Callable<Boolean> { |
线程的常用方法
- 1.start()启动线程
- 2.sleep()
- 3.getName()
- 4.setName()
1 | // 设置线程的名字 |
线程的中断
线程中是有一个标志位,这个标志位可以进行设置,表示当前线程是否处于中断
线程的中断
- 条件中断
- 异常中断
- stop():暴力中断,不使用
1 | // 获取当前线程中断标志位的状态 |
线程状态
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() | 中断线程,不要用这个方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
线程的同步
解决线程资源竞争的问题
synchronized
可以修饰代码块(同步代码快)
1
2
3synchronized(同步监视器){
...
}- 同步监视器
- 1.可以理解成锁。并且任何对象都可以充当锁
- 2.只有拿到锁的线程才能操作同步代码块中的代码,其他线程只能等待,等锁释放后线程再去抢这把锁
- 与共享变量操作相关的代码都放在同步代码块中,放进去之后,其他没有拿到锁的线程就没办法接触到这个共享变量,也就不会出现多个线程操作某个共享变量
可以修饰方法(同步方法)
1
2
3public synchronized void func(){
...
}- 在方法声明中加上synchronized,这样一来整个方法将会被同步,也就是只有拿到锁的线程才能执行该方法,其他线程甚至无法进入该方法
- 同步方法上的锁默认就是当前方法所在类的对象
Lock:JDK5.0中添加的
- 上锁和解锁
- Lock是一个接口,主要使用他的实现类ReentrantLock类来操作
两者区别:
synchronized相当于自动加锁解锁
Lock需要自己手动的加锁和解锁,但是他更加灵活
synchronized
1 | // 同步方法 |
Lock
1 | public void sell() { |
线程间通信
线程间通信:
以下方法必须放在syncrhonized里面,否则包参数异常!
wait() : 可以让当前线程暂停,暂停之后释放锁,其他线 程可以获取这个锁,等待其他线程唤醒
notify():唤醒某个暂停的线程
notifyAll():唤醒所有等待的线程
sleep()与wait()的区别?
他们两个都能让线程进行暂停
sleep()不会释放当前线程占用的锁
wait()会释放锁
线程池
1 | // 创建包含5个线程的线程池对象 |
阿里Java开发手册禁止使用Executors创建线程池:
- 【强制】线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors各个方法的弊端:
1) newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2) newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
- 【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。
1 | public static void main(String[] args) { |