spring|Java程序员必会的三个技能: Spring+MySQL+并发编程( 二 )


       System.out.println(\"Stopping application...\");    

3、notify()和 notifyAll()有什么区别?
notify 可能会导致死锁 , 而 notifyAll 则不会
任何时候只有一个线程可以获得锁 , 也就是说只有一个线程可以运行 synchronized 中的代码使用 notifyall可以唤醒所有处于 wait 状态的线程 , 使其重新进入锁的争夺队列中 , 而 notify 只能唤醒一个 。
wait() 应配合 while 循环使用 , 不应使用 if , 务必在 wait()调用前后都检查条件 , 如果不满足 , 必须调用 notify()唤醒另外的线程来处理 , 自己继续 wait()直至条件满足再往下执行 。
notify() 是对 notifyAll()的一个优化 , 但它有很精确的应用场景 , 并且要求正确使用 。 不然可能导致死锁 。 正确的场景应该是 WaitSet 中等待的是相同的条件 , 唤醒任一个都能正确处理接下来的事项 , 如果唤醒的线程无法正确处理 , 务必确保继续 notify()下一个线程 , 并且自身需要重新回到 WaitSet 中 。
4、sleep()和 wait() 有什么区别?
对于 sleep()方法 , 我们首先要知道该方法是属于 Thread 类中的 。 而 wait()方法 , 则是属于 Object 类中
的 。
sleep()方法导致了程序暂停执行指定的时间 , 让出 cpu 该其他线程 , 但是他的监控状态依然保持者 , 当指定的时间到了又会自动恢复运行状态 。 在调用 sleep()方法的过程中 , 线程不会释放对象锁 。
当调用 wait()方法的时候 , 线程会放弃对象锁 , 进入等待此对象的等待锁定池 , 只有针对此对象调用 notify()方法后本线程才进入对象锁定池准备 , 获取对象锁进入运行状态 。
5、volatile 是什么?可以保证有序性吗?
一旦一个共享变量(类的成员变量、类的静态成员变量)被 volatile 修饰之后 , 那么就具备了两层语义:
(1)保证了不同线程对这个变量进行操作时的可见性 , 即一个线程修改了某个变量的值 , 这新值对其他线程来说是立即可见的volatile 关键字会强制将修改的值立即写入主存 。
(2)禁止进行指令重排序 。
volatile 不是原子性操作
什么叫保证部分有序性?
当程序执行到 volatile 变量的读操作或者写操作时 , 在其前面的操作的更改肯定全部已经进行 , 且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;
x = 2;//语句 1
y = 0;//语句 2
flag = true;//语句 3
x = 4;//语句 4
y = -1;//语句 5

由于?ag 变量为 volatile 变量 , 那么在进行指令重排序的过程的时候 , 不会将语句 3 放到语句 1、语句 2 前面 , 也不会讲语句 3 放到语句 4、语句 5 后面 。 但是要注意语句 1 和语句 2 的顺序、语句 4 和语句 5 的顺序是不作任何保证的 。
使用 Volatile 一般用于 状态标记量 和 单例模式的双检锁
6、Thread 类中的 start() 和 run() 方法有什么区别?
start()方法被用来启动新创建的线程 , 而且 start()内部调用了 run()方法 , 这和直接调用 run()方法的效果不一样 。 当你调用 run()方法的时候 , 只会是在原来的线程中调用 , 没有新的线程启动 , start()方法才会启动新线程 。
7、为什么 wait notify 和 notifyAll 这些方法不在 thread 类里面?
明显的原因是 JAVA 提供的锁是对象级的而不是线程级的 , 每个对象都有锁 , 通过线程获得 。 如果线程需要等待某些锁那么调用对象中的 wait()方法就有意义了 。 如果 wait()方法定义在 Thread 类中 , 线程正在等待的是哪个锁就不明显了 。 简单的说 , 由于 wait , notify 和 notifyAll 都是锁级别的操作 , 所以把他们定义在 Object 类中因为锁属于对象 。
8、为什么 wait 和 notify 方法要在同步块中调用?
(1)只有在调用线程拥有某个对象的独占锁时 , 才能够调用该对象的 wait()notify()和 notifyAll()方法 。


推荐阅读