关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象。本文探讨Lock对象。
synchronized与java.util.concurrent.locks.Lock 的相同点:Lock能完成synchronized所实现的所有功能;主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放, 并且必须在finally从句中释放。
一:先来一段简单的代码
packagecom.clzhang.sample.thread;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;public class LockThread1 implementsRunnable {private Integer key = 0;//锁对象
private Lock lock = newReentrantLock();
@Overridepublic voidrun() {//需要结果是key实现自增长,如果没有同步块,则可能会出现重复key值的现象
lock.lock();try{
key++;
System.out.println(Thread.currentThread().getName()+ ":" +key);try{
Thread.sleep(10);
}catch(InterruptedException e) {
}
}finally{//上述代码实现功能与使用sychronized同步代码块一样。//sychronized同步代码块或同步方法在代码执行完之后锁自动释放;而用Lock则需要手工释放锁。//为了保证锁最终被释放,释放锁代码放在finally块内。
lock.unlock();
}
}public static voidmain(String[] args) {
LockThread1 lt= newLockThread1();for(int i=0; i<100; i++) {new Thread(lt, "Thread" +i).start();
}
}
}
部分输出:
Thread86:95
Thread88:96
Thread90:97
Thread98:98
Thread92:99
Thread96:100
二:再来一段稍复杂的代码
packagecom.clzhang.sample.thread;import java.util.*;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;public class LockThread2 implementsRunnable {//内部类
classStudent {private int age = 0;public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}
}//全局变量定义
private int count = 0;private Student student = newStudent();//锁对象
private Lock lock1 = new ReentrantLock(false);private Lock lock2 = new ReentrantLock(false);
@Overridepublic voidrun() {
String currentThreadName=Thread.currentThread().getName();
System.out.println(currentThreadName+ " is running!");
lock1.lock();//使用重入锁
System.out.println(currentThreadName + " got lock1@Step1!");try{
count++;
Thread.sleep(3000);
}catch(Exception e) {
e.printStackTrace();
}finally{
System.out.println(currentThreadName+ " first:count=" + count + "\tage=" + this.student.getAge());
lock1.unlock();
}
lock2.lock();//使用另外一个不同的重入锁
System.out.println(currentThreadName + " got lock2@Step2!");try{
Random random= newRandom();int age = random.nextInt(100);this.student.setAge(age);
Thread.sleep(3000);
}catch(Exception ex) {
ex.printStackTrace();
}finally{
System.out.println(currentThreadName+ " second:count=" + count + "\tage=" + this.student.getAge());
lock2.unlock();
}
}public static voidmain(String[] args) {
LockThread2 lt= newLockThread2();for (int i = 1; i <= 3; i++) {
Thread t= new Thread(lt, "Thread" +i);
t.start();
}
}
}
输出:
Thread1 is running!
Thread1 got lock1@Step1! // 线程1获取锁1
Thread3 is running!
Thread2 is running!
Thread1 first:count=1 age=0
Thread3 got lock1@Step1!
Thread1 got lock2@Step2! // 线程3、1分别获取锁1、2
Thread3 first:count=2 age=13
Thread1 second:count=2 age=13 // count值已经被线程3更改;age是自己设置的。
Thread3 got lock2@Step2!
Thread2 got lock1@Step1! // 线程3、2分别获取锁2、1
Thread2 first:count=3 age=34
Thread3 second:count=3 age=34 // count值已经被线程2更改;age是自己设置的。
Thread2 got lock2@Step2! // 线程2获取锁2
Thread2 second:count=3 age=40 // 没人改count值了;age是自己设置的。
三:再来一段读写的代码
要求:写入和写入互斥,读取和写入互斥,读取和读取之间不互斥。
packagecom.clzhang.sample.thread;import java.util.*;importjava.util.concurrent.locks.ReadWriteLock;importjava.util.concurrent.locks.ReentrantReadWriteLock;public class LockThread3 implementsRunnable {//数据存放
private StringBuilder sb = newStringBuilder();//锁对象
private ReadWriteLock rwl = newReentrantReadWriteLock();
@Overridepublic voidrun() {if (Thread.currentThread().getName().startsWith("Read")) {
rwl.readLock().lock();//取到读锁
try{
System.out.println(Thread.currentThread().getName()+ "正在读取...");try{
Thread.sleep(500);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "结果:" +sb.toString());
}finally{
rwl.readLock().unlock();//释放读锁
}
}else if (Thread.currentThread().getName().startsWith("Write")) {
rwl.writeLock().lock();//取到写锁
try{
System.out.println(Thread.currentThread().getName()+ "正在写入...");try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
String writeData= "" + new Random().nextInt(100);
sb.append(writeData+ ",");
System.out.println(Thread.currentThread().getName()+ "结果:" +writeData);
}finally{
rwl.writeLock().unlock();//释放写锁
}
}else{//啥也不做行不
}
}public static voidmain(String[] args) {
LockThread3 lt= newLockThread3();for (int i=0; i<5; i++) {
Thread t= new Thread(lt, "Write" +i);
t.start();
}for (int i=0; i<5; i++) {
Thread t= new Thread(lt, "Read" +i);
t.start();
}
}
}
输出:
Write1正在写入...
Write1结果:25
Write0正在写入...
Write0结果:5
Read0正在读取...
Read2正在读取...
Read4正在读取...
Read2结果:25,5,
Read0结果:25,5,
Read4结果:25,5,
Write2正在写入...
Write2结果:77
Write4正在写入...
Write4结果:38
Read1正在读取...
Read3正在读取...
Read1结果:25,5,77,38,
Read3结果:25,5,77,38,
Write3正在写入...
Write3结果:77