栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java并发编程12种锁的具体实现方式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java并发编程12种锁的具体实现方式

Java并发编程12种锁的具体实现方式
  • 代码Github下载地址
  • synchronized(常用)
  • Lock
    • lock,unlock
    • trylock
  • ReadAndWriteLock(读写锁)
  • Atomic(i++操作)
  • LongAdder(Atomic的优化)
  • CountdownLatch(门闩)
  • Exchanger(线程交换数据)
  • Locksupport(类似于lock)
  • Phaser (过程中,锁部分线程)
  • CyclicBarrier(循环栅栏)
  • Semaphore(限流)
  • Unsafe(操作内存实现线程安全-不推荐)


代码Github下载地址

点击跳转

https://github.com/MaBo2420935619/ThreadLock
synchronized(常用)

使用JDK5引进的CAS自旋之外,还增加了自适应的CAS自旋、锁消除、锁粗化、偏向锁、轻量级锁这些优化策略。由于此关键字的优化使得性能极大提高,同时语义清晰、操作简单、无需手动关闭,所以推荐在允许的情况下尽量使用此关键字,同时在性能上此关键字还有优化的空间。

锁主要存在四种状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁。但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。

public class RunnableTest implements Runnable{
    private final  static int  Max=10000;
    private final   static  int Number=100000;
    private Object object=new Object();
    private    int a=0;
    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    @Override
    public void run() {
        synchronized (object){
            for (int i = 0; i < Number; i++) {
                a++;
            }
        }
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        RunnableTest test=new RunnableTest();
        for (int i = 0; i < Max; i++) {
            Thread thread = new Thread(test::run);
            thread.start();
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        Thread threadX = new Thread(new Runnable() {
            public void run() {
                System.out.println(test.getA());
                long end = System.currentTimeMillis();
                System.out.println((end-start)+"ms");
            }
        });
        threadX.start();
    }
}

Lock

Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。

lock,unlock
package lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestReentrantLock implements Runnable {
    private   Lock lock = new ReentrantLock();

    int a=0;

    public int getA() {
        return a;
    }

    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        TestReentrantLock test = new TestReentrantLock();
        for (int i = 0; i < 1000; i++) {
            Thread thread = new Thread(test);
            thread.start();
            thread.join();
        }

        Thread threadX = new Thread(() -> {
            System.out.println(test.getA());
            long end = System.currentTimeMillis();
            System.out.println((end-start)+"ms");
        });
        threadX.start();

    }


    @Override
    public void run() {

        lock.lock();
        try {

            for (int i = 0; i < 100000; i++) {
                a++;
            }
        }finally {
            lock.unlock();
        }
    }
}

trylock
package lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestTryLock {
    private static int a=0;

    public static int getA() {
        return a;
    }

    public static void setA(int a) {
        TestTryLock.a = a;
    }

    private static Lock lock=new ReentrantLock();;
    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        TestTryLock test=new TestTryLock();

        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(test::add);
            thread.start();
            thread.join();
        }
        Thread threadX = new Thread(new Runnable() {
            public void run() {
                System.out.println(test.getA());
                long end = System.currentTimeMillis();
                System.out.println((end-start)+"ms");
            }
        });
        threadX.start();

    }
    public void add(){
        try {
            lock.tryLock(1, TimeUnit.SECONDS);
            a++;
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
}

ReadAndWriteLock(读写锁)

ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相对于排他锁,提高了并发性。在实际应用中,大部分情况下对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock能够提供比排他锁更好的并发性和吞吐量。

读写锁内部维护了两个锁,一个用于读操作,一个用于写操作。所有 ReadWriteLock实现都必须保证 writeLock操作的内存同步效果也要保持与相关 readLock的联系。也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。

ReentrantReadWriteLock支持以下功能:

1)支持公平和非公平的获取锁的方式;

2)支持可重入。读线程在获取了读锁后还可以获取读锁;写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;

3)还允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不允许的;

4)读取锁和写入锁都支持锁获取期间的中断;

5)Condition支持。仅写入锁提供了一个 Conditon 实现;读取锁不支持 Conditon ,readLock().newCondition() 会抛出 UnsupportedOperationException。

package readAndWriteLock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadAndWriteLockTest {
   static   ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
    static   Lock read=readWriteLock.readLock();
    static Lock write=readWriteLock.writeLock();

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    read.lock();
                    Thread.sleep(1000);
                    System.out.println("我在读");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    read.unlock();
                }
            }).start();
        }
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                try {
                    write.lock();
                    Thread.sleep(1000);
                    System.out.println("我在写");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    write.unlock();
                }
            }).start();
        }
    }
}

Atomic(i++操作)

原子更新类,利用CAS(CompareAndSwap)实现无锁操作,占用CPU资源。依赖CPU的原语实现。
AtomicBoolean:原子更新布尔类型。
AtomicInteger:原子更新整型。
AtomicLong:原子更新长整型。
AtomicInteger的常用方法如下:

  • int addAndGet(int delta):以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果
  • boolean compareAndSet(int expect, int update) :如果输入的数值等于预期值,则以原子方式将该值设置为输入的值。
  • int getAndIncrement():以原子方式将当前值加1,注意:这里返回的是自增前的值。
  • void lazySet(int newValue):最终会设置成newValue,使用lazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值
  • int getAndSet(int newValue):以原子方式设置为newValue的值,并返回旧值。
package atomic;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerTest implements Runnable {
    private final  static int  Max=10000;
    private final   static  int Number=100000;
    AtomicInteger atomicInteger=new AtomicInteger(0);

    public AtomicInteger getAtomicInteger() {
        return atomicInteger;
    }

    public void setAtomicInteger(AtomicInteger atomicInteger) {
        this.atomicInteger = atomicInteger;
    }

    @Override
    public void run() {
        for (int i = 0; i < Number; i++) {
            atomicInteger.incrementAndGet();
        }
    }
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        AtomicIntegerTest test=new AtomicIntegerTest();
        for (int i = 0; i < Max; i++) {
            Thread thread = new Thread(test::run);
            thread.start();
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        Thread threadX = new Thread(new Runnable() {
            public void run() {
                System.out.println(test.getAtomicInteger());
                long end = System.currentTimeMillis();
                System.out.println((end-start)+"ms");
            }
        });
        threadX.start();
    }
}

LongAdder(Atomic的优化)

LongAdder是一种以空间换时间的解决方案。其内部维护了一个值base,和一个cell数组,当线程写base有冲突时,将其写入数组的一个cell中。将base和所有cell中的值求和就得到最终LongAdder的值了。

package LongAdder;

import java.util.concurrent.atomic.LongAdder;

public class LongAdderTest implements Runnable {
    private final  static int  Max=1000;
    private final   static  int Number=100000;
    LongAdder longAdder = new LongAdder();
    public LongAdder getLongAdder() {
        return longAdder;
    }
    public void setLongAdder(LongAdder longAdder) {
        this.longAdder = longAdder;
    }

    @Override
    public void run() {
        for (int i = 0; i < Number; i++) {
            longAdder.increment();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        LongAdderTest test=new LongAdderTest();
        for (int i = 0; i < Max; i++) {
            Thread thread = new Thread(test::run);
            thread.start();
            thread.join();
        }

        Thread threadX = new Thread(new Runnable() {
            public void run() {
                System.out.println(test.getLongAdder());
                long end = System.currentTimeMillis();
                System.out.println((end-start)+"ms");
            }
        });
        threadX.start();
    }
}

CountdownLatch(门闩)

CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。

CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。

package countdownLatch;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class CountdownLatchTest {
    static int a=0;
    public static void main(String[] args) throws InterruptedException {

        Lock lock=new ReentrantLock(true);
        Thread threads[]=new Thread[100];
        CountDownLatch countDownLatch=new CountDownLatch(threads.length);

        for (Thread t : threads) {
            t=new Thread(() -> {
                try {
                    lock.lock();
                    a++;
                    countDownLatch.countDown();
                } finally {
                    lock.unlock();
                }
            });
            t.start();
        }
        countDownLatch.await();
        System.out.println(a);
    }
}

Exchanger(线程交换数据)

Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据, 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。因此使用Exchanger的重点是成对的线程使用exchange()方法,当有一对线程达到了同步点,就会进行交换数据。因此该工具类的线程对象是成对的。
Exchanger类提供了两个方法,String exchange(V x):用于交换,启动交换并等待另一个线程调用exchange;String exchange(V x,long timeout,TimeUnit unit):用于交换,启动交换并等待另一个线程调用exchange,并且设置最大等待时间,当等待时间超过timeout便停止等待。

package exchanger;

import java.util.concurrent.Exchanger;

public class ExchangerTest {
   static Exchanger exchanger=new Exchanger<>();
    static class Show implements Runnable{
        private String name;

        public Show(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
               name= exchanger.exchange(name);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            System.out.println(name);
        }
    }
    public static void main(String[] args) {
        Exchanger exchanger=new Exchanger<>();
        Thread thread1=new Thread(new Show("1"),"t1");
        Thread thread2=new Thread(new Show("2"),"t2");
        thread1.start();
        thread2.start();
    }
}

Locksupport(类似于lock)
  • park和unpark可以实现类似wait和notify的功能,但是并不和wait和notify交叉,也就是说unpark不会对wait起作用,notify也不会对park起作用。
  • park和unpark的使用不会出现死锁的情况
  • blocker的作用是在dump线程的时候看到阻塞对象的信息
package locksupport;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

public class LocksupportTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    if (i ==3) {
                        LockSupport.park();
                    }
                    System.out.println(i);
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        });
        thread.start();
        TimeUnit.SECONDS.sleep(6);
        LockSupport.unpark(thread);
    }
}

Phaser (过程中,锁部分线程)

Phaser类似于CountdownLatch,但是Phaser可以有多个周期。

package phaser;

import java.util.concurrent.Phaser;

public class PhaserTest {
    public static void main(String[] args) {
        WorkPhaser workPhaser=new WorkPhaser();
        workPhaser.bulkRegister(3);
        for (int i = 1; i < 4; i++) {
            Person person = new Person(workPhaser, String.valueOf(i));
            Thread thread=new Thread(person,String.valueOf(i));
            thread.start();
        }
    }
    private static class Person implements Runnable{
        private Phaser phaser;
        private String name;

        public Person(Phaser phaser, String name) {
            this.phaser = phaser;
            this.name = name;
        }

        @Override
        public void run() {
            work1();
            work2();
            work3();
        }
        private void work1(){
            String playerName = Thread.currentThread().getName();
            System.out.println(playerName+"     吃");
            phaser.arriveAndAwaitAdvance();
        }
        private void work2(){
            String playerName = Thread.currentThread().getName();
            if (playerName.equals("1")||playerName.equals("2")){
                System.out.println(playerName+"     上厕所");
                phaser.arriveAndAwaitAdvance();
            }
            else {
                System.out.println(playerName+"     不上厕所");
                phaser.arriveAndDeregister();
            }
        }
        private void work3() {
            String playerName = Thread.currentThread().getName();
            if (playerName.equals("2")||playerName.equals("3")){
                System.out.println(playerName+"     回家");
                phaser.arriveAndAwaitAdvance();
            }
            else {
                System.out.println(playerName+"     不回家");
                phaser.arriveAndDeregister();
            }
        }
    }
    private static class WorkPhaser extends Phaser {
        @Override
        protected boolean onAdvance(int phase, int registeredParties) {
            switch (phase) {
                case 0:
                    System.out.println("所有人都到吃"+registeredParties);
                    return false;
                case 1:
                    System.out.println("1和2一起上厕所"+registeredParties);
                    return false;
                case 2:
                    System.out.println("2和3一起回家"+registeredParties);
                    return true;
                default:
                    return true;
            }
        }

    }

}

CyclicBarrier(循环栅栏)

作用就是会让所有线程都等待完成后才会执行

package cyclicBarrier;

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    // 自定义工作线程
    private static class Worker implements Runnable {
        private static CyclicBarrier cyclicBarrier=new CyclicBarrier(5);

        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + "开始等待其他线程");
                cyclicBarrier.await();
                System.out.println(Thread.currentThread().getName() + "执行");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {

        for (int i = 0; i < 100; i++) {
            System.out.println("创建工作线程" + i);
            Thread thread=new Thread(new Worker());
            thread.start();

        }
    }
}

Semaphore(限流)

限制线程可以同时运行的数量

package semaphore;

import java.util.concurrent.Semaphore;

public class SemaphoreTest {
    public static void main(String[] args) {
        Semaphore semaphore=new Semaphore(2);
        for (int i = 0; i < 6; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        for (int j = 0; j < 2; j++) {
                            Thread.sleep(1000);
                            System.out.println(Thread.currentThread().getName());
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    finally {
                        semaphore.release();
                    }

                }
            }).start();
        }
    }
}

Unsafe(操作内存实现线程安全-不推荐)

较为底层的一中线程锁的方法,不安全。

package myLock;

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class TestUnsafe {
    volatile int n = 0;
    private static Unsafe unsafe = null;
    private static long fieldOffset;

    static {
        Field unsafe1 = null;//获取Unsafe的theUnsafe属性
        try {
            unsafe1 = Unsafe.class.getDeclaredField("theUnsafe");
            unsafe1.setAccessible(true);
            unsafe = (Unsafe) unsafe1.get(null);//unsafe实例对象

            Field n1 = TestUnsafe.class.getDeclaredField("n");
            fieldOffset = unsafe.objectFieldOffset(n1);//获取偏移量
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }


    }

    public void add() {
        int intVolatile = unsafe.getIntVolatile(this, fieldOffset);//获取值
        for (; ; ) {//防止伪唤醒
            unsafe.compareAndSwapInt(this, fieldOffset, intVolatile, intVolatile + 1);// add  +1
            break;
        }
    }

    public static void main(String[] args) {
        TestUnsafe testUnsafe = new TestUnsafe();
        for (int i = 0; i < 100; i++) {//创建6个线程实现
            new Thread(() -> {
                testUnsafe.add();
            }).start();
        }
        try {
            Thread.sleep(6000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(testUnsafe.n);
    }

}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/601984.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号