Java学习笔记-05线程
API中创建线程的两种方式
- 方式一:继承Thread类
1) 定义子类继承Thread类。
2) 子类中重写Thread类中的run方法。
3) 创建Thread子类对象,即创建了线程对象。
4) 调用线程对象start方法:启动线程,调用run方法。
- 方式二:实现Runnable接口
1) 定义子类,实现Runnable接口。
2) 子类中重写Runnable接口中的run方法。
3) 通过Thread类含参构造器创建线程对象。
4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
- 多线程出现了安全问题
问题的原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有 执行完,另一个线程参与进来执行。导致共享数据的错误。
解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以 参与执行。
- 方式一:同步代码块
synchronized (对象){ // 需要被同步的代码; }
同步代码块:自己指定,很多时候也是指定为this或类名.class
- 方式二:同步方法
public synchronized void show (String name){ …. }
同步方法的锁:静态方法(类名.class)、非静态方法(this)
- 方式三:Lock锁
java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的 工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象 加锁,线程开始访问共享资源之前应先获得Lock对象。
ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和 内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以 显式加锁、释放锁。
- 线程的通信
wait() 与 notify() 和 notifyAll()
wait():令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当 前线程排队等候其他线程调用notify()或notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有 权后才能继续执行。
notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待。
notifyAll ():唤醒正在排队等待资源的所有线程结束等待.
这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报 java.lang.IllegalMonitorStateException异常。
- JDK5新增线程创建方式
- 实现Callable接口:重写call()方法,作为参数传入FurtherTask,并调用其get()方法。再传入Thread,调用start()方法
- call()有返回值
- call()可以抛出异常,被外面的操作捕获,获取异常信息
- Callable支持泛型
- 使用线程池(多用)
- 提高响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程管理:核心池的大小、最大线程数、线程最多保持时间
- ExecutorService:真正的线程池接口 .execute适用于Runnable .submit适用于Callable .shutfdown关闭线程池
- Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
- 实现Callable接口:重写call()方法,作为参数传入FurtherTask,并调用其get()方法。再传入Thread,调用start()方法