异常分析:java.lang.IllegalMonitorStateException

java.lang.IllegalMonitorStateException



JavaDoc上关于IllegalMonitorStateException的解释是:

Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.

其实意思就是说,也就是当前的线程不是此对象监视器的所有者。也就是要在当前线程锁定对象,才能用锁定的对象此行这些方法,需要用到synchronized ,锁定什么对象就用什么对象来执行  notify()notifyAll(),wait()wait(long)wait(long, int)操作,否则就会报IllegalMonitorStateException异常。


JavaDoc中说到:

A thread becomes the owner of the object's monitor in one of three ways:
1. By executing a synchronized instance method of that object.
2. By executing the body of a synchronized statement that synchronizes on the object.
3. For objects of type Class, by executing a synchronized static method of that class. 

通过以下三种方法之一,线程可以成为此对象监视器的所有者:

  • 通过执行此对象的同步 (Sychronized) 实例方法。
  • 通过执行在此对象上进行同步的 synchronized 语句的正文。
  • 对于 Class 类型的对象,可以通过执行该类的同步静态方法。

也就是在说,就是需要在调用wait()或者notify()之前,必须使用synchronized语义绑定住被wait/notify的对象。


下面介绍解决方法:

通过实现加锁的方式实现线程同步时产生的并发问题.


exapmle 1,锁定方法所属的实例对象:
public synchronized void method(){
    //然后就可以调用:this.notify()...
    //或者直接调用notify()...
}



exapmle 2,锁定方法所属的实例的Class:
public Class Test{
 public static synchronized void method(){
    //然后调用:Test.class.notify()...
 }
}



exapmle 3,锁定其他对象:
public Class Test{
public Object lock = new Object();
 public static void method(){
    synchronized (lock) {
     //需要调用 lock.notify();
    } 
 }
}


总结:

:“线程操作的wait()、notify()、notifyAll()方法只能在同步控制方法或同步控制块内调用。如果在非同步控制方法或控制块里调用,程序能通过编译,但运行的时候,将得到  IllegalMonitorStateException 异常,并伴随着一些含糊信息,比如 ‘当前线程不是拥有者’。其实异常的含义是 调用wait()、notify()、notifyAll()的任务在调用这些方法前必须 ‘拥有’(获取)对象的锁。”


下面附录线程的基本使用知识:



一、线程的理解


 1、同个应用中,多个任务同时进行。就像QQ聊天,打开一个聊天窗口就是一个线程。

 2、线程可以有多个,但cpu每时每刻只做一件事。由于cpu处理速度很快,我们就感觉是同时进行的。所以宏观上,线程时并发进行的;从微观角度看,线程是异步执行的。

 3、使用线程的目的是最大限度的利用cpu资源。想想QQ聊天的时候,如果没有多线程,一个人的信息没有发完另一个人的信息发不过来,会是什么情况~!



二、java中使用线程

 

1、创建线程

eg1:继承Thread

class MyThread extends Thread{
    @Override
    public void run() {
     //code
    }
}

启动线程方法:new MyThread().start();

eg2:实现Runnable接口

class MyRunnable implements Runnable {
    @Override
    public void run() {
        //code
    }
}

启动线程方法:new Thread(new MyRunnable()).start();

 


2、设置线程优先级

Thread t = new Thread(myRunnable);
t.setPriority(Thread.MAX_PRIORITY);//一共10个等级,Thread.MAX_PRIORITY表示最高级10
t.start();



3、join,sleep,yield的用法与区别

  join方法:假如你在A线程中调用了B线程的join方法B.join();,这时B线程继续运行,A线程停止(进入阻塞状态)。等B运行完毕A再继续运行。

  sleep方法:线程中调用sleep方法后,本线程停止(进入阻塞状态),运行权交给其他线程。

  yield方法:线程中调用yield方法后本线程并不停止,运行权由本线程和优先级不低于本线程的线程来抢。(不一定优先级高的能先抢到,只是优先级高的抢到的时间长)

 


4、结束线程(修改标示符flag为false来终止线程的运行)

 
public class ThreadTest {
    public static void main(String[] args) {
        A aa = new A();
        Thread tt = new Thread(aa);
        tt.start();

        try {
            Thread.sleep(5000);
        } catch (Exception e) {
            e.printStackTrace();
        }

        aa.shutDown();
    }
}

class A implements Runnable {
    private boolean flag = true;

    public void run() {
        while (flag) {
            System.out.println("AAAA");
        }
    }

    public void shutDown() {
        this.flag = false;
    }
}
 

 


5、线程同步synchronized

  synchronized可以修饰方法,或者方法内部的代码块。被synchronized修饰的代码块表示:一个线程在操作该资源时,不允许其他线程操作该资源。

 
public class ThreadTest {

    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
    }

}

class MyRunnable implements Runnable {
    private int i = 0;

    @Override
    public void run() {
        while (true) {
            sumNum();
        }
    }

    private synchronized void sumNum() {
        if (i < 100) {
            try {
                Thread.sleep(1000);
                i ++;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "--------"
                    + i);
        }
    }

}
复制代码

 


6、wait、notify、notifyAll的用法

  wait方法:当前线程转入阻塞状态,让出cpu的控制权,解除锁定。

  notify方法:唤醒因为wait()进入阻塞状态的其中一个线程。

  notifyAll方法: 唤醒因为wait()进入阻塞状态的所有线程。

  这三个方法都必须用synchronized块来包装,而且必须是同一把锁,不然会抛出java.lang.IllegalMonitorStateException异常。

 

下面是一个生产者、消费者例子:

 
public class ProductConsumer {
    public static int i = 0;

    public static void main(String[] args) {
        ProductStack ps = new ProductStack();
        Product product = new Product(ps);
        new Thread(product).start();

        Consumer consumer = new Consumer(ps);
        new Thread(consumer).start();
    }

}

class Product implements Runnable {
    ProductStack ps = null; 
    Product(ProductStack ps) {
        this.ps = ps;
    }
    @Override
    public void run() {
        while (true) {
            if (ProductConsumer.i < 100) {
                ps.push();
            }else{
                break;
            }
        }
    }

}

class Consumer implements Runnable {
    ProductStack ps = null;
        Consumer(ProductStack ps) {
            this.ps = ps;
        }

    @Override
    public void run() {
        while (true) {
            if (ProductConsumer.i < 100) {
                ps.pop();
            }else{
                break;
            }
        }
    }

}

class ProductStack {
    boolean isPro = true;
    public synchronized void push() {
        if (!isPro) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        notifyAll();
        ProductConsumer.i++;
        System.out.print("第" + ProductConsumer.i + "个产品,生产者:"
                + Thread.currentThread().getName());
        isPro = false;
        try {
            Thread.sleep((int) Math.random() * 200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }

    public synchronized void pop() {
        if (isPro) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        notifyAll();
        System.out.println(",消费者:" + Thread.currentThread().getName());
        isPro = true;
        try {
            Thread.sleep((int) Math.random() * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

 

  



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章