话题一:多线程的3种创建方式
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程,如下所示:
1)继承Thread类创建线程
2)实现Runnable接口创建线程
3)使用Callable和Future创建线程
话题二:wait和notify的理解与使用
-
案例分析wait和notify
- wait和notify知识补充:首先要理解notify()和wait(),因为这两个方法本来就不属于Thread类,而是属于最底层的object基础类的,也就是说不光是Thread,每个对象都有notify和wait的功能,为什么?
因为他们是用来操纵锁的,而每个对象都有锁,锁是每个对象的基础,既然锁是基础的,那么操纵锁的方法当然也是最基础了.
话题三:同样是线程休眠:wait(),sleep(),suspend()有什么区别呢?
-
wait:让当前线程阻塞,同时又“积极”地等待条件发生改变,这一点很关键,sleep和suspend无法做到.
1)因为我们有时候需要通过同步(synchronized)的帮助来防止线程之间的冲突,而一旦使用同步,就要锁定对象,也就是获取对象锁,其它要使用该对象锁的线程都只能排队等着,等到同步方法或者同步块里的程序全部运行完才有机会.在同步方法和同步块中,无论sleep()还是suspend()都不可能自己被调用的时候解除锁定,他们都霸占着正在使用的对象锁不放
2) 而wait却可以,它可以让同步方法或者同步块暂时放弃对象锁,而将它暂时让给其它需要对象锁的人(这里应该是程序块,或线程)用,这意味着可在执行wait()期间调用线程对象中的其他同步方法!在其它情况下(sleep啊,suspend啊),这是不可能的.
3) 但是注意我前面说的,只是暂时放弃对象锁,暂时给其它线程使用,我wait所在的线程还是要把这个对象锁收回来的!
-
sleep:
-
suspend:
话题四:wait()暂时放弃对象锁后,如何将对象锁收回来?
- 第一种方法,限定借出去的时间.在wait()中设置参数,比如wait(1000),以毫秒为单位,就表明我只借出去1秒中,一秒钟之后,我自动收回:wait(long timeout);
- 第二种方法,让借出去的人通知我,他用完了,要还给我了.这时,我马上就收回来:notify();
- PS:.哎,假如我设了1小时之后收回,别人只用了半小时就完了,那怎么办呢?靠!当然用完了就收回了,还管我设的是多长时间啊!
话题五:线程的可用方法展示
- notify():通知
- wait():等待
- run():执行
话题六:synchronized和volatile?
1.volatile问题引出
// 老师演示的时候,有一个问题,虽然子线程falg=true,但是main线程打印依然是false!但是在我的JDK上没有重现这一个现象
public class TestVolatile {
public static void main(String[] args) throws Exception {
// 1.创建一个线程
MyThreadA myThreadA = new MyThreadA();
new Thread(myThreadA).start();
new Thread(myThreadA).start();
// 2.mian主线程
while(true){
if (myThreadA.flag) {
System.out.println("-------------主线程flag:"+myThreadA.flag);
Thread.sleep(1000);
}else{
System.out.println("*************主线程flag:"+myThreadA.flag);
Thread.sleep(1000);
}
}
}
}
class MyThreadA implements Runnable{
public boolean flag = Boolean.FALSE;
@Override
public void run() {
try {
System.out.println("-----------自定义线程执行休眠1s");
Thread.sleep(200);
flag = Boolean.TRUE;
System.out.println("-----------休眠结束flag:"+flag);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.synchronized(object){}代表什么含义?
- 只能由一个线程同时使用object
- 多线程时,先判断锁,有锁就要将后续线程阻塞挂起,直到下一次CPU重新给他进行任务分配
- 加锁的这种效率是最低的!但是又需要刷新数据(内存可见性的问题),怎么办?--volatile
- volatile可以保证多个线程在访问相同数据时候,数据是实时可见的(实时将缓存数据刷新到主存中)!
3.synchronized和volatile比较
- volatile对比于synchronized,是一种轻量级的同步策略!
- volatile不具备"互斥性",不能保证只有一个线程使用共享数据
- volatile不能保证变量的原子性
4.什么是原子性?
i++ 的原子性问题:i++ 的操作实际上分为三个步骤“读-改-写”
int i = 10;
i = i++; //10
int temp = i;
i = i + 1;
i = temp;
- 本身来说,i++不能将过程进行拆解,但是volatile不能保证原子性,如果在多线程下就会被拆开,数据的执行结果就会出错!
网友评论