java多线程和线程锁的思考

1、当前线程的状态,所持有的锁是否释放

持有锁的线程不释放锁
线程执行同步代码块或同步方法时,程序调用Thread.sleep(Long l)、Thread.yield()方法暂停当前线程的执行,不释放锁;
线程执行同步代码块时,其它线程调用该线程suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)
尽量避免使用suspend()和resume()来控制线程


持有锁的线程会释放锁
当前线程的同步方法、同步代码块执行结束
当前线程的同步方法、同步代码块遇到break、return终止该代码块、该方法的继续执行
当前线程的同步方法、同步代码块中出现了未处理Error和Exception,导致异常结束
当前线程在同步方法、同步代码块中执行了线程所属对象的wait()方法,当前线程暂停,并释放锁

所以说:

* 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内(下面的代码锁对象就是queue,先获得该对象,再在代码块中使用wait()和notify()方法阻塞唤醒线程)

* 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A

* 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行

* 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)

* obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行

* 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。

 1 public class Test {
 2     private int queueSize = 10;
 3     private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
 4      
 5     public static void main(String[] args)  {
 6         Test test = new Test();
 7         Producer producer = test.new Producer();
 8         Consumer consumer = test.new Consumer();
 9          
10         producer.start();
11         consumer.start();
12     }
13      
14     class Consumer extends Thread{
15          
16         @Override
17         public void run() {
18             consume();
19         }
20          
21         private void consume() {
22             while(true){
23                 synchronized (queue) {
24                     while(queue.size() == 0){
25                         try {
26                             System.out.println("队列空,等待数据");
27                             queue.wait();
28                         } catch (InterruptedException e) {
29                             e.printStackTrace();
30                             queue.notify();
31                         }
32                     }
33                     queue.poll();          //每次移走队首元素
34                     queue.notify();
35                     System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
36                 }
37             }
38         }
39     }
40      
41     class Producer extends Thread{
42          
43         @Override
44         public void run() {
45             produce();
46         }
47          
48         private void produce() {
49             while(true){
50                 synchronized (queue) {
51                     while(queue.size() == queueSize){
52                         try {
53                             System.out.println("队列满,等待有空余空间");
54                             queue.wait();
55                         } catch (InterruptedException e) {
56                             e.printStackTrace();
57                             queue.notify();
58                         }
59                     }
60                     queue.offer(1);        //每次插入一个元素
61                     queue.notify();
62                     System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
63                 }
64             }
65         }
66     }
67 }

wait()/sleep()的区别
  前面讲了wait/notify机制,Thread还有一个sleep()静态方法,它也能使线程暂停一段时间。sleep与wait的不同点是:sleep并不释放锁,并且sleep的暂停和wait暂停是不一样的。obj.wait会使线程进入obj对象的等待集合中并等待唤醒。
  但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException。
  如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在wait/sleep/join,则线程B会立刻抛出InterruptedException,在catch() {} 中直接return即可安全地结束线程。
  需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一线程调用interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是,一旦该线程进入到wait()/sleep()/join()后,就会立刻抛出InterruptedException。

查看Object.wait()API 描述如下:

    Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0). 

    The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

其中“the thread releases ownership of this monitor” 说道当前线程会释放这个对象监控器的所有权。



原文:https://blog.csdn.net/csdn_g_y/article/details/79751803

原文:http://www.cnblogs.com/dolphin0520/p/3932906.html

猜你喜欢

转载自www.cnblogs.com/ws-zhuli/p/10899925.html