首先,讲讲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被中断了