Day19
----------------------------------------------------------------------------------
今天内容:
(1)线程的常用方法
(2)线程的同步机制
1.线程常用方法(重点)
static void sleep(long millis) - 用于让当前正在执行的线程休眠参数指定的毫秒数。
- 1秒 = 1000毫秒 1毫秒 = 1000微秒 1微秒 = 1000纳秒
int getPriority() - 用于获取调用对象所代表线程的优先级。
void setPriority(int newPriority) - 用于更改线程的优先级为参数指定的数值。
- 优先级越高的线程表示获取时间片的机会越多,但不保证一定先执行。
void join() - 用于使得当前正在执行的线程等待调用对象所代表的线程终止。
void join(long millis) - 等待调用对象所代表线程的时间最长为参数指定的毫秒数。
boolean isDaemon() - 用于测试调用对象是否为守护线程。
void setDaemon(boolean on) - 用于将调用对象设置为守护线程。
- 该方法必须在调用start()方法前使用。
- 当所有非守护线程结束后,则守护线程随之结束,Java虚拟机也就结束。
2.线程的同步机制(重点、难点)
2.1 基本概念
当多个线程同时访问同一种共享资源时,可能会造成数据的覆盖等不一致性问题,此时就需要对线程之间进行协调和通信,该方式就叫线程的同步机制。
如:
03年左右 存折 银行卡 对应同一个账户
2.2 解决方案
由程序可知:当两个线程同时执行取款200元的操作时,导致最终的账户余额不正确。
引发原因:当第一个线程取款后还没来得及改变账户余额,第二个线程就已经开始执行。
解决方案:将两个线程取款操作的并发执行修改为串行执行即可。
带来问题:执行效率比较低,因此应该尽量减少串行的范围。
2.3 实现方式
在Java语言中使用synchronized关键字来实现同步/对象锁的效果,来保证每个线程执行的原子性,具体使用方式如下:
(1)使用同步语句块的方式实现,语法格式为:
synchronized(对象的引用){
编写所有需要锁定的语句块;
}
(2)使用同步方法的方式实现,直接使用synchronized关键字修饰整个方法即可。
等价于 synchronized(this){}的方式。
2.4 实现原理
当多个线程同时启动后则开始抢占共享资源,若其中一个线程抢到共享资源则使用对象锁将资源锁定后使用,其它线程进入阻塞状态,直到该线程执行完毕锁定内容后释放对象锁,此时阻塞的线程又开始抢占共享资源,抢到资源的线程继续锁定,抢不到的线程继续等待。
2.5 死锁的概念(了解)
线程一执行的代码:
public void run(){
synchronized(a){ //持有对象锁a等待对象锁b
synchronized(b){
...
}
}
}
线程二执行的代码:
public void run(){
synchronized(b){ //持有对象锁b等待对象锁a
synchronized(a){
...
}
}
}
注意:
在以后的开发中尽量不要使用同步语句块的嵌套结构。
2.6 Object类中的常用方法
void wait() - 用于使得当前线程进入等待状态,直到其它线程调用notify()/notifyAll()
void wait(long timeout) - 除了其它线程调用notify()/notifyAll()方法外,还有参数
指定的毫秒数过去了也可以解除等待状态。
void notify() - 用于唤醒等待的任意单个线程。
void notifyAll() - 用于唤醒等待的所有线程。
作业:
1.复习和理解线程同步机制。
2.参考并编写学生信息管理系统的案例。
3.有余力的同学自己编写生产者消费者模型的案例。