非法监控状态异常java

Posted

技术标签:

【中文标题】非法监控状态异常java【英文标题】:Illegal monitor state exception java 【发布时间】:2016-04-20 12:23:38 【问题描述】:

我有一个将 json 对象写入文件的类用户

public class User 

    public static void main(String args[]) throws IOException, org.json.simple.parser.ParseException
        writetofile();
        Q q= new Q();
        Writer write = new Writer("write",q);
//      System.out.println(q.queue.poll());
        Reader reader = new Reader("read",q);
    
    public static void writetofile() throws IOException
        FileWriter file = new FileWriter("file1.txt");
        for(int i=0;i<3;++i)
            JSONObject obj = new JSONObject();
            obj.put("Name", rand_s());
            obj.put("Age", rand_i());
            file.write(obj.toJSONString());
            file.flush();
            file.write("\r\n");
    //      System.out.println("Successfully Copied JSON Object to File...");
        //  System.out.println("\nJSON Object: " + obj);
        
    
    public static String rand_s()
        final String AB = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        SecureRandom rnd = new SecureRandom();
        StringBuilder sb = new StringBuilder( 12 );
           for( int i = 0; i < 12; i++ ) 
              sb.append( AB.charAt( rnd.nextInt(AB.length()) ) );
           return sb.toString();
    
    public static String rand_i()
        final String AB = "0123456789";
        SecureRandom rnd = new SecureRandom();
        StringBuilder sb = new StringBuilder( 2 );
           for( int i = 0; i < 2; i++ ) 
              sb.append( AB.charAt( rnd.nextInt(AB.length()) ) );
           return sb.toString();
    

我有一个将 Json 文档从文件写入队列的类编写器和一个从队列中读取并打印对象并将它们从队列中删除的类读取器

下面是作家类

package org.mmt;

import java.io.File;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Scanner;

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

public class Writer implements Runnable 
    Thread t;
    Q q;
    Writer(String name,Q q)
        t= new Thread(this,name);
        this.q = q;
        t.start();
    
    @Override
    public void run()
        String FileName="file1.txt";
        try 
            ArrayList<JSONObject> jsons=ReadJSON(new File(FileName),"UTF-8");
            for(JSONObject ob1 : jsons)
                q.put(ob1);
                notifyAll();
//              System.out.println(q.queue.poll());
            
         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (ParseException e) 
            e.printStackTrace();
         catch (org.json.simple.parser.ParseException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
    
    public static synchronized ArrayList<JSONObject> ReadJSON(File MyFile,String Encoding) throws FileNotFoundException, ParseException, org.json.simple.parser.ParseException 
        Scanner scn=new Scanner(MyFile,Encoding);
        ArrayList<JSONObject> json=new ArrayList<JSONObject>();
    //Reading and Parsing Strings to Json
        while(scn.hasNext())
            JSONObject obj= (JSONObject) new JSONParser().parse(scn.nextLine());
            json.add(obj);
        
        return json;
    


下面是阅读器类

package org.mmt;

import java.util.Queue;

import org.json.simple.JSONObject;

public class Reader implements Runnable 

    Thread t;
    Q q;
    Reader(String name,Q q)
        t=new Thread(this,name);
        this.q=q;
        t.start();
    
    public void run() 
        // TODO Auto-generated method stub
        while(!q.empty())
            JSONObject obj = new JSONObject();
            obj = q.get();
            System.out.println(obj);
        
        while(q.empty())
            try 
                wait();
             catch (InterruptedException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        
    

下面是 Q 类,其中包含必须写入数据的队列

package org.mmt;

import java.util.LinkedList;
import java.util.Queue;

import org.json.simple.JSONObject;


public class Q 
    public Queue<JSONObject> queue = new LinkedList<JSONObject>();
    public synchronized JSONObject get()
        return queue.poll();
    
    public synchronized void put(JSONObject obj)
        try
        queue.add(obj);
        
        catch (Exception e)
            System.out.println(e);
        
    
    public boolean empty()
        return queue.isEmpty();
    

我已经在读取器和写入器中启动线程以同时读取和写入,并且每当队列为空时读取器类 waits() 以及每当写入器将元素写入队列时,我使用 notifyall() 让读取器恢复但我得到非法监视器状态例外。我搜索了互联网,发现每当线程尝试锁定它不拥有但我无法解决问题的监视器时就会发生这种情况

【问题讨论】:

使用BlockingQueue 会更容易(也更整洁)。 【参考方案1】:

您的ReaderWriter 类需要共享 监控对象。在您的示例中,Reader 将自己用作监视器,Writer 将自己用作监视器。

在您的情况下,您可以将Queue q 本身用作监视器,因为这是您需要同步的状态。 调用者也需要拥有监视器,他们通常拥有这样的所有权: syncronized (q) //do stuff on q 换句话说,wait/notify 应该只在一个同步块中调用,该块在对象上是同步的。

More about wait/notify here

【讨论】:

【参考方案2】:

您收到该异常是因为您不在监视器中

public class User 
    public static final Object lock = new Object();

    ...

    synchronized(User.lock) 
        while(q.empty())
            try 
                wait();
             catch (InterruptedException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        
    

public class Writer implements Runnable 
    ...
        for(JSONObject ob1 : jsons)
            q.put(ob1);
            synchronized(User.lock) 
                notifyAll();
            
     //     System.out.println(q.queue.poll());
        

请注意,我已经有一段时间没有使用过synchronized 和这样的并发了,所以我不确定这是否完全是线程安全的。

主要是因为如果你最终得到

synchronized(lock) 
    synchronized(Q) 

synchronized(Q) 
    synchronized(lock) 

然后你会在某个时候遇到死锁,你的应用程序将冻结。这就是我个人对synchronized 方法持谨慎态度的原因。

【讨论】:

以上是关于非法监控状态异常java的主要内容,如果未能解决你的问题,请参考以下文章

onActivityResult 中的非法状态异常

JPA 非法状态异常 - CascadeType 问题

jython 中的 SSL 非法状态异常

mMap.addPolyline 抛出非法状态异常

javaFX Alert抛出无法捕获的非法状态异常?

Crashlytics.logException 方法抛出非法状态异常。无法收集某些活动的非致命问题