Java NIO提供Lock对象来实现对当前对象加锁。
1,Lock接口方法详解:
void lock()
获取锁。如果锁不可用,出现线程调度,将会禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态。
void lockInterruptibly() throws InterruptedException;
如果当前线程未被中断则获取锁。如果锁可用则获取锁,并立即返回。如果锁不可用出现线程调度会禁用当前线程,除非发生以下情况,否则该线程会一直休眠:-1,当前线程获取锁。-2,其他线程终端当前线程,并且该线程支持对锁获取的中断。
boolean tryLock()
仅在调用时锁为空闲状态才获取该锁。如果锁可用则立即获取锁,返回true。如果锁不可用,则此方法返回false。
void unlock()
释放锁。在获取锁操作后,需要进行释放锁。
2,Lock与synchronized
Lock比synchronized更加的灵活,且具有以下优势:
允许以一种更加灵活的方式构造synchronized块。使用synchronized,必须以结构化的方式释放锁。Lock接口允许更加灵活的实现临界区。
Lock实现更多额外的功能,比如tryLock
Lock支持读写分离。
3,多线程模拟打印队列。
package chp1.atomic.print;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 打印队列
*
* @author jinglongjun
*
*/
public class PrintQueue {
private final Lock queueLock = new ReentrantLock();
/**
* 模拟打印任务
*
* @param document
*/
public void printJob(Object document) {
try {
// 获取锁
queueLock.lock();
Long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName()
+ ":PrintQueue: Printing a Job during " + (duration / 1000)
+ " seconds");
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放锁
queueLock.unlock();
}
}
}
package chp1.atomic.print;
public class Job implements Runnable {
private PrintQueue printQueue;
public Job(PrintQueue printQueue) {
this.printQueue = printQueue;
}
@Override
public void run() {
System.out.printf("%s: Going to print a document\n", Thread
.currentThread().getName());
printQueue.printJob(new Object());
System.out.printf("%s: The document has been printed\n", Thread
.currentThread().getName());
}
}
package chp1.atomic.print;
public class Main {
public static void main(String[] args) {
PrintQueue printQueue = new PrintQueue();
Thread thread[] = new Thread[10];
for (int i = 0; i < 10; i++) {
thread[i] = new Thread(new Job(printQueue), "Thread " + i);
}
for (int i = 0; i < 10; i++) {
thread[i].start();
}
}
}
4,死锁
通过Lock获取对象的时候,应该特别注意死锁问题,A线程锁定x,B线程锁定y,而当B线程试图锁定x,A视图锁定y的时候即会发生死锁。曾经在面试的时候被要求写一个死锁程序。
package chp1.atomic.DeadLock;
public class DeadLock {
public static void main(String[] args) {
final Object x = new Object();
final Object y = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (x) {
System.out.println(" t1 synchronized x");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (y) {
System.out.println("t1 synchronized y ");
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (y) {
System.out.println(" t2 synchronized y");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (x) {
System.out.println("t2 synchronized x ");
}
}
}
});
t1.start();
t2.start();
}
}
运行时输出以下语句然后一直等待:
t1 synchronized x
t2 synchronized y
通过jstack命令可以查看是否存在死锁。
jstack -l 33674
2016-04-04 21:35:39
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.79-b02 mixed mode):
"Attach Listener" daemon prio=5 tid=0x0000000128162000 nid=0x2365f waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Process monitor" daemon prio=5 tid=0x0000000102137000 nid=0x1a843 in Object.wait() [0x000070000426b000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007f5997a38> (a java.lang.UNIXProcess)
at java.lang.Object.wait(Object.java:503)
at java.lang.UNIXProcess.waitFor(UNIXProcess.java:261)
- locked <0x00000007f5997a38> (a java.lang.UNIXProcess)
at org.eclipse.debug.core.model.RuntimeProcess$ProcessMonitorThread.run(RuntimeProcess.java:426)
Locked ownable synchronizers:
- None
参考:
http://ifeve.com/basic-thread-synchronization-5/
http://www.blogjava.net/xylz/archive/2010/07/05/325274.html
http://ifeve.com/basic-thread-synchronization-8/