首先,讲讲synchronized关键字,java的内置特性。在java中synchronized作为关键字可以修饰代码块或者方法,当使用它修饰代码块或者方法时,表示被修饰的代码块或者方法,同一时刻只能被一个线程执行或调用,其他线程会处于等待状态,当占用锁的进程执行完成后,jvm会自动释放锁及线程执行所分配的线程空间,这时其他线程才可以继续获取锁。
例如:
同时起两个线程A和B,run方法中的业务代码块被synchronized修饰,lock为同步代码的锁,当线程A占用lock锁10s,线程B只能等待10s后才能获取lock继续执行代码块。
public void run (){
synchronized (lock) {
Thread.sleep(10000);
system.out.printIn("线程A---");
}
}
public void run(){
synchronized (lock) {
system.out.printIn("线程B---");
}
}
以上是synchronized关键字最基本的用法,但是也有缺点,当一个线程一直占用锁,其他线程只能等待锁被释放,当线程并发量很多时,需要占用很多的资源,服务器的负载一下子会突增,导致服务器崩溃。因此后续的java版本中concurrent中提供了ReentrantLock类解决了这个问题,ReenttrantLock类提供了Lock,tryLock,lockInterruptibly等多种针对锁机制处理的API接口。当然NIO也能解决这个问题,这里不做赘述。
接下来讲讲ReenttrantLock类提供的Lock,tryLock,lockInterruptibly三个API。
Lock方法:是一个接口,Lock的原理基本与synchronized相似,但是不同于synchronized的地方是,synchronized是jvm自动释放锁,Lock需要手动释放。缺点:Lock如果发生异常时,有可能没有进行unlock操作,导致死锁,synchronized发生异常会自动释放锁,不会发生死锁。Lock在应用中更灵活,可以中断、设置等待获取的时间、判断是否获取锁成功、但synchronized无法做到,可以提高多个线程读操作的效率。如果有大量线程并发竞争是,Lock的性能要比synchronized好的多,具体应当根据适用场景进行选择。
Lock实例演示:
package com.huawei.bigdata.zkdist;
import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class TestLock {
private static ArrayList<Integer> arraylist = new ArrayList<Integer>();
static Lock lock = new ReentrantLock(); //创建锁对象
public static <E> void main(String[] args) {
new Thread(){
public void run() {
String tname = Thread.currentThread().getName();
try {
lock.lock();//线程0获取锁
System.out.println(tname+"得到了锁");
for (int i = 0; i < 5; i++) {
arraylist.add(i);
}
} catch (Exception e) {
// TODO: handle exception
}finally {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();//线程0释放了锁
System.out.println(tname+"释放了锁");
}
};
}.start();
new Thread(){
public void run() {
String tname = Thread.currentThread().getName();
try {
lock.lock();
System.out.println(tname+"得到了锁");
for (int i = 0; i < 5; i++) {
arraylist.add(i);
}
} catch (Exception e) {
// TODO: handle exception
}finally {
lock.unlock();
System.out.println(tname+"释放了锁");
} };
}.start();
}
}
运行结果:
Thread-0得到了锁
Thread-0释放了锁
Thread-1得到了锁
Thread-1释放了锁
tryLock方法:tryLock返回的是boolean值,当同时又多个线程去获取锁时,如果线程A获取到了锁,A线程会去继续执行自己的业务代码,同一时间因为锁被A线程占用,B没有获取到锁,返回false,反之为true。此时就可以根据返回值对B线程的业务代码做进一步处理,不会发生一致等待的情况。如果想让B线程等待N时间后再返回获取锁的结果,可以使用tryLock(N,unit),其他N参数为指定的等待时间。
tryLock实例演示:
package com.huawei.bigdata.zkdist;
import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class TestTryLock {
static ArrayList<String> testlist = new ArrayList<String>();
static Lock lock = new ReentrantLock();
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
String tname = Thread.currentThread().getName();
boolean tryLock = lock.tryLock();
System.out.println(tname + "获得了锁");
for (int i = 0; i < 5; i++) {
testlist.add("hi,");
}
System.out.println(tname+"释放了锁");
}
}.start();
new Thread(){
public void run() {
String tname = Thread.currentThread().getName();
boolean tryLock = lock.tryLock();
System.out.println(tname+" "+tryLock);
if(tryLock){
System.out.println(tname+"获得了锁");
for (int i = 0; i < 5; i++) {
testlist.add("hello");
}
lock.unlock();
System.out.println(tname+"释放了锁");
}
};
}.start();
}
}
运行结果:
Thread-0获得了锁
Thread-0释放了锁
Thread-1 false
lockInterruptibly方法:假如同时有线程A和线程B去获取锁,A获取到了,如果B调用了lockInterruptibly方法,这时B线程可以在等待的过程中主动中断等待,处理其他的事情。
lockInterruptibly实例演示:
package com.huawei.bigdata.zkdist;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class TestLockInterruptibly {
Lock lock = new ReentrantLock(); public static void main(String[] args) {
TestLockInterruptibly test = new TestLockInterruptibly();
MyThread thread0 = new MyThread(test);
MyThread thread1 = new MyThread(test);
thread0.start();
thread1.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
thread1.interrupt();
System.out.println("=====================");
}
public void insert(Thread thread) throws InterruptedException{
lock.lockInterruptibly();
try {
System.out.println(thread.getName()+"获取到了锁");
long startTime = System.currentTimeMillis();
for (; ; ) {
if(System.currentTimeMillis()-startTime>=Integer.MAX_VALUE){
break;
}
}
} finally {
// TODO: handle finally clause
System.out.println(Thread.currentThread().getName()+"执行了finally");
lock.unlock();
System.out.println(Thread.currentThread().getName()+"释放了锁");
}
}
}class MyThread extends Thread{
private TestLockInterruptibly test = null;
public MyThread(TestLockInterruptibly test) {
// TODO Auto-generated constructor stub
this.test = test;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
test.insert(Thread.currentThread());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println(Thread.currentThread().getName()+"被中断了");
}
}
}
运行结果:
Thread-0获取到了锁
=====================
Thread-1被中断了