ReentrantLock实现生产者消费者和死锁
一、实现生产者消费者(线程交替执行)
Conditon中的await()对应Object的wait(),Condition中的signal()对应Object的notify(),Condition中的signalAll()对应Object的notifyAll()
condition.await()方法:使当前线程等待,直到收到信号或被中断。与此条件相关联的锁被原子释放。当前线程处于休眠状态,当其他一些线程为这个条件调用signalAll方法或signal方法时,当前线程被唤醒,然后重新获取与此条件相关联的锁
两个线程交替执行例子(同理生产者消费者也是这样交替执行):
package com.yang.spbo.other.lock; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; /** * A,B两个线程交替执行 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class ConditionService { private ReentrantLock lock = new ReentrantLock(); /** * 两个线程所以创建两个condition */ private Condition A = lock.newCondition(); private Condition B = lock.newCondition(); private int number = 1; private boolean flag = false; private void executeA() { while (number < 100) { try { lock.lock(); if (!flag) { System.out.println("A等待"); A.await(); } System.out.println("A " + number); number++; flag = false; System.out.println("B唤醒"); B.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } private void executeB() { while (number < 100) { try { lock.lock(); if (flag) { System.out.println("B等待"); B.await(); } System.out.println("B " + number); number++; flag = true; System.out.println("A唤醒"); A.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public static void main(String[] args) { final ConditionService cs = new ConditionService(); ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 1, TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>(1000), new MyThreadFactory("conditionService")); executor.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); cs.executeA(); } }); executor.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); cs.executeB(); } }); } static class MyThreadFactory implements ThreadFactory { /** * 线程名字前缀 */ private String namePrefix; private AtomicInteger id = new AtomicInteger(1); public MyThreadFactory(String namePrefix) { this.namePrefix = namePrefix; } @Override public Thread newThread(Runnable r) { String threadName = namePrefix + "-worker-" + id.getAndIncrement(); Thread thread; thread = new Thread(r, threadName); return thread; } } }
运行结果:
conditionService-worker-1
A等待
conditionService-worker-2
B 1
A唤醒
B等待
A 2
B唤醒
A等待
B 3
A唤醒
B等待
A 4
B唤醒
A等待
B 5
A唤醒
B等待
A 6
二、死锁
什么是死锁?
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源(相互请求锁定对方已经锁定占用的资源),从而导致恶性循环等待的现象
如:两个线程都在锁内等待获取对方持有的锁。
如何避免死锁?
1)避免一个线程同时获取多个锁
2)避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
3)尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制
4)对于数据库锁,加锁和解锁必须在同一个数据库连接里,否则会出现解锁失败的情况
ReentrantLock实现死锁:
/** * ReentrantLock实现死锁 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class DeadLockTest { private static ReentrantLock lock1 = new ReentrantLock(); private static ReentrantLock lock2 = new ReentrantLock(); public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { lock1.lock(); try { Thread.sleep(1000); lock2.lock(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock1.unlock(); } } }).start(); new Thread(new Runnable() { @Override public void run() { lock2.lock(); try { Thread.sleep(1000); lock1.lock(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock2.unlock(); } } }).start(); } }
分析过程:
1.
c:\Program Files\Java\jdk1.7.0_79\bin>jps
7996 Main
3960 Jps
8396 Launcher
5568 Launcher
1204
8212 Bootstrap
396 ProfilerServer
7996 Main
3960 Jps
8396 Launcher
5568 Launcher
1204
8212 Bootstrap
396 ProfilerServer
8036 DeadLockTest
2.c:\Program Files\Java\jdk1.7.0_79\bin>jstack 8036
Found one Java-level deadlock:
=============================
"Thread-1":
waiting for ownable synchronizer 0x00000007d5e6f5c0, (a java.util.concurrent.l
ocks.ReentrantLock$NonfairSync),
which is held by "Thread-0"
"Thread-0":
waiting for ownable synchronizer 0x00000007d5e6f5f0, (a java.util.concurrent.l
ocks.ReentrantLock$NonfairSync),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007d5e6f5c0> (a java.util.concurrent.lock
s.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInt
errupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(A
bstractQueuedSynchronizer.java:867)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(Abstrac
tQueuedSynchronizer.java:1197)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLo
ck.java:214)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:290)
at deadLock.DeadLockTest$2.run(DeadLockTest.java:38)
at java.lang.Thread.run(Thread.java:745)
"Thread-0":
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007d5e6f5f0> (a java.util.concurrent.lock
s.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInt
errupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(A
bstractQueuedSynchronizer.java:867)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(Abstrac
tQueuedSynchronizer.java:1197)
=============================
"Thread-1":
waiting for ownable synchronizer 0x00000007d5e6f5c0, (a java.util.concurrent.l
ocks.ReentrantLock$NonfairSync),
which is held by "Thread-0"
"Thread-0":
waiting for ownable synchronizer 0x00000007d5e6f5f0, (a java.util.concurrent.l
ocks.ReentrantLock$NonfairSync),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007d5e6f5c0> (a java.util.concurrent.lock
s.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInt
errupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(A
bstractQueuedSynchronizer.java:867)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(Abstrac
tQueuedSynchronizer.java:1197)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLo
ck.java:214)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:290)
at deadLock.DeadLockTest$2.run(DeadLockTest.java:38)
at java.lang.Thread.run(Thread.java:745)
"Thread-0":
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007d5e6f5f0> (a java.util.concurrent.lock
s.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInt
errupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(A
bstractQueuedSynchronizer.java:867)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(Abstrac
tQueuedSynchronizer.java:1197)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLo
ck.java:214)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:290)
at deadLock.DeadLockTest$1.run(DeadLockTest.java:24)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
补充:
synchronized实现死锁:
/** * synchronized实现死锁 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class DeadLockTest2 { private static Object obj1 = new Object(); private static Object obj2 = new Object(); public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { synchronized (obj1) { System.out.println("thead1 get lock1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj2) { System.out.println("thead1 get lock2"); } System.out.println("thread1 end"); } } }, "thead1").start(); new Thread(new Runnable() { @Override public void run() { synchronized (obj2) { System.out.println("thead2 get lock2"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj1) { System.out.println("thead2 get lock1"); } System.out.println("thread2 end"); } } }, "thead2").start(); } }
Found one Java-level deadlock:
=============================
"thead2":
waiting to lock monitor 0x000000000b15a7c8 (object 0x00000007d5e6f290, a java.
lang.Object),
which is held by "thead1"
"thead1":
waiting to lock monitor 0x000000000b1593d8 (object 0x00000007d5e6f2a0, a java.
lang.Object),
which is held by "thead2"
Java stack information for the threads listed above:
===================================================
"thead2":
at deadLock.DeadLockTest2$2.run(DeadLockTest2.java:44)
- waiting to lock <0x00000007d5e6f290> (a java.lang.Object)
- locked <0x00000007d5e6f2a0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"thead1":
at deadLock.DeadLockTest2$1.run(DeadLockTest2.java:27)
- waiting to lock <0x00000007d5e6f2a0> (a java.lang.Object)
- locked <0x00000007d5e6f290> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
=============================
"thead2":
waiting to lock monitor 0x000000000b15a7c8 (object 0x00000007d5e6f290, a java.
lang.Object),
which is held by "thead1"
"thead1":
waiting to lock monitor 0x000000000b1593d8 (object 0x00000007d5e6f2a0, a java.
lang.Object),
which is held by "thead2"
Java stack information for the threads listed above:
===================================================
"thead2":
at deadLock.DeadLockTest2$2.run(DeadLockTest2.java:44)
- waiting to lock <0x00000007d5e6f290> (a java.lang.Object)
- locked <0x00000007d5e6f2a0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"thead1":
at deadLock.DeadLockTest2$1.run(DeadLockTest2.java:27)
- waiting to lock <0x00000007d5e6f2a0> (a java.lang.Object)
- locked <0x00000007d5e6f290> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
END.