多线程理解
1.多线程的创建方式
- 创建Thread类的子类,重写run方法,调用start方法开启线程
- 创建实现Runnable接口的类,重写run方法,创建Thread类的对象时,将实现类的对象作为参数传进去,并用Thread类的对象调用start方法开启线程。
2.两种多线程比较
优先选择实现Runnable接口的方式
- 实现的方式没有类的单继承性的局限性
- 实现的方式更适合来处理多个线程有共享数据的情况。
3.联系
Thread implements Runnable
两种方式都需要重写run,线程的逻辑都需要写在run中
4.对多线程的理解
- 一个进程可以细分为多个线程
- 一个线程拥有独立的PC和虚拟机栈
- 多个线程,共享同一个进程中的结构:方法区、堆
- 一个java应用程序java.exe,最少三个线程:
- main()主线程
- gc()垃圾回收线程
- 异常处理线程
5.线程的生命周期
6.线程安全问题
出现错误数据。
方式一
使用synchronized
-
同步代码块
-
同步方法
- 同步方法仍然涉及到锁,只是不需要显式的声明
- 非静态的同步方法,锁是this
- 静态的同步方法,锁是当前类本身
方式二
使用lock锁
方式三
实现Callable接口
方式四
使用线程池
使用线程池的好处
- 提高响应速度(减少的创建线程池的时间)
- 降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
- 便于线程管理
异同
synchronized遇lock的异同?
-
相同:两者都能解决线程安全问题
-
不同:
- synchronized机制在执行完相应的同步代码块后,自动释放同步监视器
- lock需要手动启动同步,手动关闭同步
7.死锁
- 死锁的理解:不同线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成的线程的死锁
- 说明:出现死锁后,不会出现异常,程序不会结束,不出现提示,所有线程都处于阻塞状态,无法继续
8.线程通信
wait(),当前线程进入阻塞状态,并释放同步监视器
notify(),唤醒被wait的一个线程,如果多个线程被wait,则优先唤醒优先级高的线程
notifyAll()唤醒所有被wait的线程
1.这三个方法必须使用在同步代码块或者同步方法中。
2.这三个方法的调用者必须是同步代码块或同步方法中的同步监视器
3.这三个方法是定义在Object类中的
sleep和wait方法的异同?
- 都可以使当前线程进入阻塞状态
- 两个方法声明的位置不同,sleep声明在thread中,wait声明在Object中,
- 调用的要求不同,sleep可以在任何需要的场景下使用,wait必须在同步代码块或同步方法中使用
- sleep不释放同步监视器,而wait释放
sleep声明在thread中,wait声明在Object中, - 调用的要求不同,sleep可以在任何需要的场景下使用,wait必须在同步代码块或同步方法中使用
- sleep不释放同步监视器,而wait释放