第12章 多线程
1、理解线程
进程:每个独立执行的程序称为进程。
线程:线程是一个进程内部的一条执行路径。
多线程 :在一个进程中有多条执行路径。
线程与进程的区别:
(1)、每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大。
(2)、同一进程内的多个线程共享相同的代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程间的切换开销小。
2、线程的创建和启动
有两种方式创建线程类:
实现Runnable 接口
继承自Thread 类
理解:Thread 实现了接口Runnable,所以新建线程类可以实现Runnable接口,也可以继承自Thread类,但无论哪种方式,在线程启动前,都要转换成Thread 或子类的对象。一般常用实现接口的方式 ,这样还可以继承自别的类或实现更多的接口,而且Thread提供的方法,有一部分是静态的,可以直接用类名调用。
启动方法:调用Thread 实例的方法:start();
3、线程的生命周期
new 一个新建的尚未启动的线程处于这种状态。
runnable当一个新建线程调用start()方法后,进入准备状态,此时线程并不一定执行了,只有获得了CPU时才开始执行,称为就绪状态。另外,当阻塞线程被释放、等待线程被唤醒、超时过期的线程也会进入该状态。
blocked 阻塞、锁定。
waiting 等待。
Thread.sleep();睡眠
Thread.yield();让步
Thread.jion(); 加入
terminated 当一个线程正常的完成了,或是因为异常而退出,则进入此状态,称为中断状态。
4、线程同步
一、synchronized 同步关键字
(1)、同步方法:
[访问修饰符] synchronized 返回值类型 方法名称(参数列表){ }
表示当前的整个方法都是同步的。
(2)、同步代码块
synchronized(this){ }
二、对象锁lock
通过Lock 接口的实现类:可重入锁ReentrantLock,可以创建锁的实例 Lock lock = new ReentrantLock();
然后调用ReentrantLock的方法进行封锁与解锁:
lock.lock(); lock.unlock();
通常lock()方法比synchronized 代码块更广泛的锁定操作,lock()允许更灵活的结构。
5、集合类的同步
(1)、使用synchronized 同步块
(2)、使用集合工具类同步化集合类的对象 如:synchronizedSet
(3)、使用并发集合类 java.util.concurrent
6.Timer定时器
java.util.Timer 类来定时执行任务
java.util.TimerTask 类代表要执行的任务
schedule和scheduleAtFixedRate的区别在于,如果指定开始执行的时间在当前系统运行时间之前,
scheduleAtFixedRate会把已经过去的时间也作为周期执行,而schedule不会把过去的时间算上。
比如
SimpleDateFormat fTime = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date d1 = fTime.parse("2005/12/30 14:10:00");
t.scheduleAtFixedRate(new TimerTask(){public void run()
{System.out.println("this is task you do6");}},d1,3*60*1000);
间隔时间是3分钟,指定开始时间是2005/12/30 14:10:00,如果我在14:17:00分执行这个程序,那么会立刻打印3次
this is task you do6 //14:10this is task you do6 //14:13this is task you do6 //14:16
并且注意,下一次执行是在14:19 而不是 14:20。就是说是从指定的开始时间开始计时,而不是从执行时间开始计时。
但是上面如果用schedule方法,间隔时间是3分钟,指定开始时间是2005/12/30 14:10:00,那么在14:17:00分执行这个程序,
则立即执行程序一次。并且下一次的执行时间是 14:20,而不是从14:10开始算的周期(14:19)。