Java中Lock,tryLock,lockInterruptibly区别和使用,及synchronized关键字

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值