Java中的锁

2020-07-20  本文已影响0人  被虐的小鸡

锁的种类

1.类锁
持有该类的字节码对象的锁

public static synchronized void  xx(){}
public void xx(){
    synchronized(xx.class){

    }
}

2.对象锁
持有该类对象的锁,前两种持有的是XX.this,最后一种持有的是成员变量的锁

public synchronized void xx(){}
public void xx(){
    synchronized(this){
    }
}
Object obj=new Object();
public void xx(){
    synchronized(obj){
    }
}

3.显示锁
显示锁就是程序员在代码中可以控制加锁,释放锁的操作。类锁和对象锁都是使用synchronized关键字来加锁,他在native帮我们完成了加锁和释放锁的操作,因此synchronized也被称为内置锁。

ReentrantLock lock=new ReentrantLock();
public void xx(){
    lock.lock();
    xxxxxxxxx;
    lock.unlock();
}

Synchronized和ReentrantLock

这两种锁都是重入锁,代表在递归方法中还可以继续获取锁,内部有一个计数器来计算我们获取同一个锁的次数
这两种锁都是非公平锁
new ReentrantLock(true);是公平锁
非公平锁效率比较高

public synchronized void xx(){
    xxxxxxxxxx;
    xx();
}

wait和notify

wait和notify都必须在synchronized中使用。因为notify和wait在进行操作时都必须获取当前锁,但是当执行完wait和notify之后会释放自己持有的锁。

public synchronized void xx(){
      xxxxxxxxxxxx;
      notify();
      wait();
}

生产者和消费者

模拟生产和消费者去生产和消费面包

public class Test {
    static class Container{
        private int id;
        private boolean flag;

        public synchronized void out(){

            if (flag) {
                System.out.println("当前线程:" + Thread.currentThread().getName() + ",消费了" + this.id);

                flag=false;
                notify();

                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public synchronized void put(){
            if (!flag) {
                id += 1;

                System.out.println("当前线程:" + Thread.currentThread().getName() + "------------------,生产了" + this.id);

                flag=true;

                notify();

                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    static class ProduceThread implements Runnable{
        private Container container;

        public ProduceThread(Container container) {
            this.container = container;
        }

        @Override
        public void run() {

            for (int i = 0; i < 20; i++) {
                container.put();
            }
        }
    }

    static class ConsumerThread implements Runnable{
        private Container container;

        public ConsumerThread(Container container) {
            this.container = container;
        }

        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                container.out();
            }
        }
    }

    public static void main(String[] args) {
        Container container = new Container();

        new Thread(new ProduceThread(container)).start();

        new Thread(new ConsumerThread(container)).start();
    }

}

之前面试遇到过相似的题目

有一个数组,{1,2,3,4,5,6...},使用两个线程,线程A打印奇数,线程B打印偶数
解决方案:

public class Demo {
    
    static class Print{
        private int i=0;
        private int[] data;
        private boolean flag;

        public Print(int[] data) {
            this.data = data;
        }

        public synchronized void printJ(){
            if (!flag){
                System.out.println(data[i]);
                i++;
                flag=true;

                notify();

                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public synchronized void printO(){
            if (flag){
                System.out.println(data[i]);

                i++;

                flag=false;

                notify();

                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class A extends Thread{
        private Print print;

        public A(Print print) {
            this.print = print;
        }

        @Override
        public void run() {
            super.run();
            while (print.i<print.data.length){
                print.printJ();
            }
        }
    }

    static class B extends Thread{
        private Print print;

        public B(Print print) {
            this.print = print;
        }

        @Override
        public void run() {
            super.run();
            while (print.i<print.data.length){
                print.printO();
            }
        }
    }


    public static void main(String[] args) {
        Print print = new Print(new int[]{1, 2, 3, 4, 5});
        new A(print).start();
        new B(print).start();
    }
}
上一篇下一篇

猜你喜欢

热点阅读