java:一个 wait(timeout) 引出的你可能对锁的误解

在很多讲 wait(long timeout)的例子,都会用下面类似的代码:

 

public class RunA implements Runnable {

    private Object lock;

    public RunA(Object lock) {
        this.lock = lock;
    }

  @Override
   public void run() {

      synchronized (lock){
          try  {
               System.out.println("A begin");
              // lock.wait(); // 永远等待着,不会执行下去
               lock.wait(2000);// 等待了 2 秒之后,继续执行下去
               System.out.println("A end");
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
  }
}

public class RunA implements Runnable { private Object lock; public RunA(Object lock) { this.lock = lock; } @Override public void run() { synchronized (lock){ try { System.out.println("A begin"); // lock.wait(); // 永远等待着,不会执行下去 lock.wait(2000);// 等待了 2 秒之后,继续执行下去 System.out.println("A end"); } catch (InterruptedException e) { e.printStackTrace(); } } } }public class RunA implements Runnable { private Object lock; public RunA(Object lock) { this.lock = lock; } @Override public void run() { synchronized (lock){ try { System.out.println("A begin"); // lock.wait(); // 永远等待着,不会执行下去 lock.wait(2000);// 等待了 2 秒之后,继续执行下去 System.out.println("A end"); } catch (InterruptedException e) { e.printStackTrace(); } } } }

举这样的例子显然是没有任何意义的,在这里用 wait(2000)和 sleep(2000) 有什么区别呢?

wait 和 sleep 显然是有很大的区别,但区别不只是 wait 会把 lock 释放掉,然我们引入一个新的搅和线程 B

public class RunB implements Runnable {

    private Object lock;

    public RunB(Object lock) {
        this.lock = lock;
    }

    @Override
  public void run() {

        synchronized (lock) {
            System.out.println("b come");
            while (true) {
            }
        }
    }
}

public class RunB implements Runnable { private Object lock; public RunB(Object lock) { this.lock = lock; } @Override public void run() { synchronized (lock) { System.out.println("b come"); while (true) { } } } }public class RunB implements Runnable { private Object lock; public RunB(Object lock) { this.lock = lock; } @Override public void run() { synchronized (lock) { System.out.println("b come"); while (true) { } } } }

B 仅仅是握住锁,然后永远不释放,然后回到我们的主舞台 main 函数:

public static void main(String[] args) throws InterruptedException {

    Object lock = new Object();
    Thread threadA = new Thread(new RunA(lock));
    threadA.start();
    threadA.wait();

    Thread.sleep(1000);

    Thread threadB = new Thread(new RunB(lock));
    threadB.start();

}

public static void main(String[] args) throws InterruptedException { Object lock = new Object(); Thread threadA = new Thread(new RunA(lock)); threadA.start(); threadA.wait(); Thread.sleep(1000); Thread threadB = new Thread(new RunB(lock)); threadB.start(); }public static void main(String[] args) throws InterruptedException { Object lock = new Object(); Thread threadA = new Thread(new RunA(lock)); threadA.start(); threadA.wait(); Thread.sleep(1000); Thread threadB = new Thread(new RunB(lock)); threadB.start(); }

然后再 run 一下,发现 A end ying 永远不会打印了,咦,为啥 wait(2000)之后没有被唤醒执行下去了呢?

仔细想想 A 显示获得了锁,然后 wait(2000)交出了锁,然后 B 拿到了锁,这个时候过了 2 秒,A 确实是被唤醒了,但很可惜 A 永远也不会得到锁了,对于临界区永远只能有一个线程在执行,不可能出现两个临界区同时在执行代码的可能,所以被唤醒之后,还需要去争抢锁,并不是唤醒了就能继续执行代码的

一个线程被唤醒可能有一下四种情况

  1. 其它的线程调用 obj.notify(),且当前线程 T,正好是被选中唤醒的。

  2. 其它的线程调用 obj.notifyAll()。

  3. 其它线程中断 T。

  4. 指定的等待时间(timeout)超时,(时间精度会有些误差)。

但我想说一下一个完整的过程是,唤醒之后需要去抢到临界区的锁,才能真正把代码执行下去,光有唤醒是不够的

大多数时候我们忽略唤醒之后需要去抢到临界区的锁,是因为 notify 用的多的关系,触发 notify 的线程必然有锁,只会唤醒一个线程,所以被唤醒的线程必然得到锁!于是大家就会产生一个被唤醒一定能执行点的错觉

而我觉得很多文章没有指明这一点,然当你意识到了这个之后,对 notifyAll 就也不会有一起全部唤醒执行的想当然理解了,notifyAll 只是让大家都去抢临界区,所有的 wait notify,都是为了保护临界区永远只能有一个在执行,分析问题还是从源头入手,见笑。。

展开阅读全文

Lock wait timeout exceeded

07-06

mysql> show processlist;rn+------+------+-----------------+--------------------+---------+------+----------rnrn+-------------------------------------------------------------------------------------------+rn| Id | User | Host | db | Command | Time | State | Info rnrn |rn+------+------+-----------------+--------------------+---------+------+----------rnrn+-------------------------------------------------------------------------------------------+rn| 4889 | root | localhost:54428 | NULL | Sleep | 7419 | | NULL rnrn |rn| 4890 | root | localhost:54429 | test_db | Sleep | 7416 | | NULL rnrn |rn| 4891 | root | localhost:54430 | information_schema | Sleep | 7411 | | NULL rnrn |rn| 4892 | root | localhost:54431 | information_schema | Query | 0 | starting | show processlist rnrn |rn| 4925 | root | localhost:54484 | test_db | Sleep | 14 | | NULL rnrn |rn| 4937 | root | localhost:54506 | test_db | Sleep | 5563 | | NULL rnrn |rn| 4962 | root | localhost:54551 | test_db | Sleep | 2345 | | NULL rnrn |rn| 4963 | root | localhost:54553 | test_db | Query | 35 | updating | update t_order set signState=1,signTime='2015-07-06 00:00:00' where rnrnid =111 |rn| 4977 | root | localhost:54581 | test_db | Sleep | 2680 | | NULL rnrn |rn| 4978 | root | localhost:54583 | test_db | Sleep | 2672 | | NULL rnrn |rn| 4979 | root | localhost:54587 | test_db | Sleep | 2708 | | NULL rnrn |rn| 4980 | root | localhost:54589 | test_db | Sleep | 2717 | | NULL rnrn |rn| 4981 | root | localhost:54590 | test_db | Sleep | 2726 | | NULL rnrn |rn| 4984 | root | localhost:54594 | test_db | Sleep | 1954 | | NULL rnrn |rn| 4991 | root | localhost:54601 | test_db | Sleep | 1766 | | NULL rnrn |rn| 4992 | root | localhost:54602 | test_db | Sleep | 215 | | NULL rnrn |rn| 4998 | root | localhost:54618 | test_db | Sleep | 1371 | | NULL rnrn |rn| 4999 | root | localhost:54619 | test_db | Sleep | 1959 | | NULL rnrn |rn| 5000 | root | localhost:54620 | test_db | Sleep | 14 | | NULL rnrn |rn| 5001 | root | localhost:54621 | test_db | Sleep | 1955 | | NULL rnrn |rn| 5002 | root | localhost:54622 | test_db | Sleep | 1956 | | NULL rnrn |rn| 5010 | root | localhost:54638 | test_db | Sleep | 1294 | | NULL rnrn |rn| 5011 | root | localhost:54639 | test_db | Sleep | 1338 | | NULL rnrn |rn| 5012 | root | localhost:54640 | test_db | Sleep | 1394 | | NULL rnrn |rn| 5028 | root | localhost:54669 | test_db | Sleep | 590 | | NULL rnrn |rn| 5029 | root | localhost:54670 | test_db | Sleep | 520 | | NULL rnrn |rn| 5038 | root | localhost:54685 | test_db | Sleep | 219 | | NULL rnrn |rn| 5039 | root | localhost:54686 | test_db | Sleep | 324 | | NULL rnrn |rn| 5045 | root | localhost:54697 | test_db | Sleep | 16 | | NULL rnrn |rn| 5046 | root | localhost:54698 | test_db | Sleep | 5 | | NULL rnrn |rn+------+------+-----------------+--------------------+---------+------+----------rnrn+-------------------------------------------------------------------------------------------+rn30 rows in setrnrnmysql> select * from innodb_lock_waits G;rn+-------------------+-------------------+-----------------+------------------+rn| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |rn+-------------------+-------------------+-----------------+------------------+rn| 89992 | 89992:357:6:96 | 89993 | 89993:357:6:96 |rn+-------------------+-------------------+-----------------+------------------+rn1 row in setrnrnmysql> select * from innodb_locks G;rn+----------------+-------------+-----------+-----------+---------------------------+------------+------------+-----------+----------+-----------+rn| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |rn+----------------+-------------+-----------+-----------+---------------------------+------------+------------+-----------+----------+-----------+rn| 89992:357:6:96 | 89992 | X | RECORD | `db`.`t_order` | PRIMARY | 357 | 6 | 96 | 111 |rn| 89993:357:6:96 | 89993 | X | RECORD | `db`.`t_order` | PRIMARY | 357 | 6 | 96 | 111 |rn+----------------+-------------+-----------+-----------+---------------------------+------------+------------+-----------+----------+-----------+rn2 rows in setrnrnmysql> rnrn程序经常卡死,重启tomcat后过一段时间又会卡死,在网上查了一些资料,有的说延长innodb_lock_wait_timeout=500,还是解决不了问题。rn上面是几张表的结果,应该怎样分析呢?rn到底是什么原因导致卡死呢? 论坛

lock wait timeout

06-18

最近在做service层的Junit测试,造了些数据写在一个Xml文件里面set进数据库,这样service层跑到了,Dao层的一些方法也调用到了,顺道都测到了,但是现在出现了lock wait timeout问题,做基本的查询,get那些可以,但是做到update,delete,edit等修改数据库数据时,却报lock的错误rnrnrnjava.sql.SQLException: Lock wait timeout exceeded; try restarting transactionrn at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)rn at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)rn at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3558)rn at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3490)rn at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959)rn at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2109)rn at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2648)rn at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2077)rn at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1356)rn at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)rn at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)rn at java.lang.reflect.Method.invoke(Unknown Source)rn at org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:100)rn at org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)rn at $java.sql.Wrapper$$EnhancerByProxool$$50e075c1.execute()rn at org.dbunit.database.statement.SimplePreparedStatement.addBatch(SimplePreparedStatement.java:80)rn at org.dbunit.database.statement.AutomaticPreparedBatchStatement.addBatch(AutomaticPreparedBatchStatement.java:70)rn at org.dbunit.operation.AbstractBatchOperation.execute(AbstractBatchOperation.java:195)rn at org.dbunit.AbstractDatabaseTester.executeOperation(AbstractDatabaseTester.java:190)rn at org.dbunit.AbstractDatabaseTester.onTearDown(AbstractDatabaseTester.java:109)rn at com.sixconnex.core.test.AbstractDbUnitTestCase.tearDown(AbstractDbUnitTestCase.java:93)rn at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)rn at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)rn at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)rn at java.lang.reflect.Method.invoke(Unknown Source)rn at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)rn at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)rn at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)rn at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:37)rn at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)rn at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)rn at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)rn at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)rn at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)rn at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)rn at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)rn at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)rn at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)rn at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)rn at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)rn at org.junit.runners.ParentRunner.run(ParentRunner.java:236)rn at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)rn at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)rn at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)rn at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)rn at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)rn at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)rn at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)rnrnrnXML数据是set进数据库的,可以看到。但后面的操作对数据库的数据无影响。还有用Debug模式可以跑完。rn 本人是新手,求各位大神帮忙,最好通俗点。。 论坛

junit测试lock wait timeout异常

12-28

rnjunit测试create update delete 等业务方法时出现mysql lock wait timeout异常java.sql.SQLException: Lock wait timeout exceeded; try restarting transactionrn at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)rn at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)rn at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3558)rn at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3490)rn at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959)rn at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2109)rn at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2648)rn at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2077)rn at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1356)rn at org.dbunit.database.statement.SimplePreparedStatement.addBatch(SimplePreparedStatement.java:67)rn at org.dbunit.database.statement.AutomaticPreparedBatchStatement.addBatch(AutomaticPreparedBatchStatement.java:57)rn at org.dbunit.operation.AbstractBatchOperation.execute(AbstractBatchOperation.java:187)rn at com.ss.base.test.SpringTxTestCase.handleTestDate(SpringTxTestCase.java:97)rn at com.ss.base.test.SpringTxTestCase.removeTestData(SpringTxTestCase.java:56)rn at com.ss.survey.service.test.SurveyOrgSetViSrvTest.finishTest(SurveyOrgSetViSrvTest.java:50)rn at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)rn at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)rn at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)rn at java.lang.reflect.Method.invoke(Unknown Source)rn at org.springframework.test.context.junit4.SpringMethodRoadie.runAfters(SpringMethodRoadie.java:297)rn at org.springframework.test.context.junit4.SpringMethodRoadie$RunBeforesThenTestThenAfters.run(SpringMethodRoadie.java:338)rn at org.springframework.test.context.junit4.SpringMethodRoadie.runWithRepetitions(SpringMethodRoadie.java:217)rn at org.springframework.test.context.junit4.SpringMethodRoadie.runTest(SpringMethodRoadie.java:197)rn at org.springframework.test.context.junit4.SpringMethodRoadie.run(SpringMethodRoadie.java:143)rn at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:142)rn at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)rn at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)rn at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)rn at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)rn at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)rn at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)rn at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)rn at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)rn at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)rn at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)rn at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)rnrn 论坛

没有更多推荐了,返回首页