java锁

前言

java并发是多线程开发中经常遇到的问题,对并发的处理,java提供了一系列的方法.机制,其中锁是其中的一个,synchronized是最常用的,而java除了synchronized同步,还有其他的同步锁,其他的可以完成其他不同的需求,以下就来说说java提供的一些锁吧~~

ReentrantLock

显示锁,可有多个条件锁,并可对某个条件进行唤醒,其中lock.newCondition()为创建一个条件,con.await()为等待此条件,con.signal()为释放一个此条件的等待,con.signalAll()为释放此条件的所有等待.当然这些操作都要遭lock.lock()与lock.unlock()中使用,不然会报错

private final Condition con;
    ReentrantLock reentrantLock;
    public ReentrantLockTest() {
        reentrantLock = new ReentrantLock();//创建显示锁
        con = reentrantLock.newCondition();//创建显示锁的一个条件

        for (int i=0;i<10;i++) {
            new TestThread().start();//启动10等待线程
        }
        new TestThread2().start();//唤醒线程
    }

    public class TestThread extends Thread {
        @Override
        public void run() {
                waitTest();

        }
    }

    public class TestThread2 extends Thread {
        @Override
        public void run() {
            for (int i=0;i<10;i++){
                try {
                    sleep(1000);//1秒唤醒一个
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                signalTest();
            }
        }
    }

    public void waitTest(){
        reentrantLock.lock();
        try {
            con.await();//等待此条件
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("testThread");
        reentrantLock.unlock();
    }

    public void signalTest(){
        reentrantLock.lock();
        con.signal();//释放此一个条件
        System.out.println("testThread2");
        reentrantLock.unlock();
    }

运行结果为


java锁_第1张图片

Semaphore

信号量,可用于同步同一时间可以运行几个线程,其中初始化时需指定型号量的数量,在这些数量被申请完后,之后申请的会被阻塞,acquire()为获取一个信号量,release()为释放一个信号量.


public class SemaphoreTest {
    final Semaphore semaphore = new Semaphore(3);//数量为3的信号量
    public SemaphoreTest() {
        for (int i=0;i<5;i++){
            new TestThread().start();
        }
    }

    public class TestThread extends Thread{
        @Override
        public void run() {
            try {
                semaphore.acquire();//获取一个型号量
                System.out.println("剩余信号量:"+semaphore.availablePermits());
                sleep(3000);
                semaphore.release();//释放信号量
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果为


其中前3个运行后需要过3秒在运行下面的两句,因为前3个将信号量用完了.

CyclicBarrier

循环栅栏,可用于等待多个线程完成某操作在一起运行之后的行为,其中初始化时需指定栅栏数,当到达这个栅栏数后会自动解锁,解锁后会将等待数清零,之后又要有指定栅栏数等待才可解锁,以此循环,也可以调用reset()来清零等待数,清零时不解锁,调用await来进行等待

public class CyclicBarrierTest {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(2);//等待栅栏数量为5

    public CyclicBarrierTest() {
        for (int i=0;i<4;i++) {
            new TestThread().start();
        }
    }

    public class TestThread extends Thread{
        @Override
        public void run() {
            try {
                System.out.println("等待");
                cyclicBarrier.await();//等待
                System.out.println("运行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果


CountDownLatch

闭锁,与循环栅栏CyclicBarrier类似,但闭锁不可重置,其中初始化时需要指定数值,在将数值减到0时会释放锁,在释放锁后再次锁不会生效,所以不可重复使用

public class CountDownLatchTest {
    CountDownLatch countDownLatch = new CountDownLatch(2);//数值为2的CountDownLatch

    public CountDownLatchTest() {

        try {
            new TestThread().start();
            countDownLatch.await();//等待
            System.out.println("等待结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public class TestThread extends Thread{
        @Override
        public void run() {
            for (int i=0;i<2;i++) {
                countDownLatch.countDown();//减一次CountDownLatch的数值
                System.out.println("减一次");
            }
        }
    }
}

运行结果


synchronized

最后说下synchronized,synchronized的使用比前面所说的锁都要方便,当然,其功能也是有限的,相当于一个单条件锁,其会将一个object对象作为一个锁条件,当此对象没被其他锁持有,将持有锁并运行下去,如有被其他锁持有则会等待锁的释放

//synchronized主要有两种用法
//1.锁方法
synchronized public void print(){
...
}
synchronized public void print2(){
...
}

//2.锁一个对象
public void print(){
synchronized(this){
...
}
}

public void print2(){
...
synchronized(this){//可以只锁方法中的一部分
...
}
}

上述的两种用法是类似的,只是锁对象可以更灵活的控制哪部分需要锁哪部分不需要,而2用法中的print()方法的效果与1用法的基本相同
需要注意的是synchronized锁的是对象,所以不同对象之间的锁不相互影响.

总结

锁是个好东西,但也不能滥用,因为其会带来一些性能上的损失,并且如果使用不当,很有可能造成死锁导致程序出问题,所以在使用锁的时候需要设计好获取与释放的逻辑.

你可能感兴趣的:(java锁)