• Java并发程序设计(四)JDK并发包之同步控制


    JDK并发包之同步控制

    一、重入锁

    重入锁使用java.util.concurrent.locks.ReentrantLock来实现。示例代码如下:

    public class TryReentrantLock implements Runnable{
    
        static ReentrantLock lock=new ReentrantLock();
        static int i=0;
        @Override
        public void run() {
            for(int j=0;j<10000;j++){
                lock.lock();
                try{
                    i++;
                }finally {
                    lock.unlock();
                }
                
                //重入锁可以反复进入,当然这种进入仅限于一个线程!因此可以如下:
                /*lock.lock(); 
                lock.lock();
                try{
                    i++;
                }finally {
                    lock.unlock();
                    lock.unlock();
                }*/
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            TryReentrantLock l=new TryReentrantLock();
            Thread t1=new Thread(l);
            Thread t2=new Thread(l);
            t1.start(); t2.start();
            t1.join(); t2.join();
            System.out.println(i);
        }
    }

    对于synchronized来说,如果一个线程在等待锁,那么结果只有两种情况,要么它获得这把锁继续执行,要么继续等待锁。而对于使用重入锁的线程来说则不同,线程在等待锁的过程中,程序可以根据需要取消对锁的请求。

    public class IntLock implements Runnable{
        public static ReentrantLock lock1=new ReentrantLock();
        public static ReentrantLock lock2=new ReentrantLock();
        int state;
    
        /*控制加锁顺序,便于产生死锁。*/
        public IntLock(int state){
            this.state=state;
        }
        @Override
        public void run() {
            try{
                if(state==1){
                    lock1.lockInterruptibly(); //设置可中断的锁
                    try{
                        Thread.sleep(500); //便于产生死锁
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    lock2.lockInterruptibly();
                }else{
                    lock2.lockInterruptibly();
                    try{
                        Thread.sleep(500);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    lock1.lockInterruptibly();
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(lock1.isHeldByCurrentThread()) lock1.unlock();
                if(lock2.isHeldByCurrentThread()) lock2.unlock();
                System.out.println(Thread.currentThread().getName()+" :quit!");
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            IntLock intLock1=new IntLock(1);
            IntLock intLock2=new IntLock(2);
            Thread t1=new Thread(intLock1);
            t1.setName("t1");
            Thread t2=new Thread(intLock2);
            t2.setName("t2");
            t1.start(); t2.start();
            Thread.sleep(1000);
            t2.interrupt();
        }
    }

    使用tryLock()进行限时等待。

    public class TimeLock implements Runnable{
        public static ReentrantLock lock=new ReentrantLock();
        @Override
        public void run() {
            try{
                if(lock.tryLock(5, TimeUnit.SECONDS)){
                    //注意返回布尔值.如果使用无参数的tryLock方法,
                    // 当锁被占用时,线程会不等待,并返回false。
                    Thread.sleep(6000);
                }else{
                    System.out.println("Get lock failed!");
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if (lock.isHeldByCurrentThread()) lock.unlock();
            }
        }
    
        public static void main(String[] args){
            TimeLock timeLock=new TimeLock();
            Thread t1=new Thread(timeLock);
            Thread t2=new Thread(timeLock);
            t1.start();
            t2.start();
    
        }
    }

    公平锁:

    大多数情况下,锁的申请都是不公平,随机的。而公平锁,讲究“先来后到”!因此公平锁的一大特点是不会产生饥饿。重入锁允许我们对其公平性进行设置:

    public ReentrantLock(boolean fair); //true表示公平锁

    公平锁缺点:性能相对低下。

    二、重入锁的好基友Condition

    Condition的做用类似于wait()和notify()只不过Condition和ReentrantLock配合。

    Condition接口的基本方法:

    void await() throws InterruptedException //释放当前线程持有的锁,进入等待状态,当其他线程使用signal或signalAll()方法时继续执行。当线程被中断时会跳出等待。
    
    void awaitUninterruptibly();与await()方法相似,当中断时不会跳出等待。
    
    void signal();
    void signalAll();

    用法示例:

    public class ReentrantCondition implements Runnable{
        static ReentrantLock lock=new ReentrantLock();
        static Condition condition=lock.newCondition();
    
        @Override
        public void run() {
            try{
                lock.lock();
                System.out.println(Thread.currentThread().getName()+" is running fast!");
                condition.await();
                System.out.println(Thread.currentThread().getName()+" is going no.");
            }catch (InterruptedException e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            ReentrantCondition rc=new ReentrantCondition();
            Thread t=new Thread(rc,"King of Lock");
            t.start();
    
            Thread.sleep(2000);
            lock.lock(); //调用signal前先要获得锁
            condition.signal();
            lock.unlock(); //调用singal后要释放锁,以让给被唤醒的线程。
        }
    }

    三、允许多个线程同时访问:信号量(Semaphore)

    Semaphore可以指定多个线程同时访问一个资源。

    public Semaphore(int permits); //permits指定同时能有几个线程访问同一资源。
    public Semaphore(int permits,boolean fair) //fair指定是否采用公平锁

    Semaphore主要的逻辑方法有:

    public void acquire()  //尝试获得一个准入许可,若无法获得,则线程会等待,直到有线程释放了一个许可,或者当前线程被中断
    public void acquireUninterruptibly() //不响应中断
    public void release() //释放一个许可

    四、ReadWriteLock读写锁

    读写锁允许多个线程同时读。

    五、CountDownLatch倒计时器

    通常用来控制线程等待,可以让某个线程等待直到倒计时结束,再开始执行。

    public CountDownLatch(int count) //count为需要完成几个线程上的任务,CountDownLatch上的线程才能继续执行。

     示例代码:

    public class CountDownLatchDemo implements Runnable{
        static final CountDownLatch latch=new CountDownLatch(10); //需要完成10个线程的任务,
        // CountDownLatch上的线程才能继续执行
        static final CountDownLatchDemo demo=new CountDownLatchDemo();
    
        @Override
        public void run() {
            try{
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+" :mission completed!");
                latch.countDown();//通知CountDownLatch一个任务已经完成。
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            ExecutorService ex= Executors.newFixedThreadPool(10);
            for(int i=0;i<10;i++){
                ex.submit(demo);
            }
    
            latch.await(); //设置要等待其他线程完成的那个线程
            System.out.println("Killed them all!");
            ex.shutdown();
        }
    }

    六、循环栅栏:CyclicBarrier

    与CountDownLatch类似CyclicBarrier也是用来阻止线程继续执行,让线程进入等待状态。但此计数器可以反复使用。

    public CyclicBarrier(int parties,Runnable barrierAction) //barrierAction为计数完成后要执行的动作

    示例代码:

    public class CyclicBarrierDemo {
    
        public static class Soldier implements Runnable{
    
            private String name;
            private final CyclicBarrier barrier;
    
            Soldier(String name,CyclicBarrier barrier){
                this.name=name;
                this.barrier=barrier;
            }
    
            @Override
            public void run() {
                try{
                    barrier.await(); //进入等待状态,直到所有线程完成计数。
                    doWork();        //所有线程完成一次await,继续执行。
                    barrier.await(); //第二次await再次进入等待状态。
                }catch (Exception e){
    
                }
            }
    
            void doWork(){
                try{
                    Thread.sleep(Math.abs(new Random().nextInt()%10000));
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("任务完成!");
            }
        }
    
        public static class FlyRun implements Runnable{
            boolean flag;
            int count;
    
            public FlyRun(boolean flag,int count){
                this.flag=flag;
                this.count=count;
            }
    
    
            @Override
            public void run() {
                if (flag) System.out.println("队长:"+count+" 个士兵完成任务!");
                else {
                    System.out.println("队长:"+count+" 个士兵集合完毕!");
                    flag=true;
                }
            }
        }
    
        public static void main(String[] args){
            final int count=12;
            Thread[] soldiers=new Thread[count];
            boolean flag=false;
            CyclicBarrier barrier=new CyclicBarrier(count,new FlyRun(flag,count));
            //集合队伍
            System.out.println("集合队伍!");
            for(int j=0;j<count;j++){
                System.out.println("士兵"+j+"报道!");
                soldiers[j]=new Thread(new Soldier("士兵"+j,barrier));
                soldiers[j].start();
            }
        }
    }

    七、线程阻塞工具类:LockSupport

    LockSupport可以在线程内任意位置让线程阻塞。但与Object.wait()不同,它不需要先获得某个对象的锁,也不会抛出InterruptedException异常。示例代码:

    public class LockSupportDemo {
    
        public static Object instance=new Object();
        public static ChangThread t1=new ChangThread("t1");
        public static ChangThread t2=new ChangThread("t2");
    
        public static class ChangThread extends Thread{
            public ChangThread(String name){
                super.setName(name);
            }
    
            @Override
            public void run(){
                synchronized(instance){
                    System.out.println("in"+getName());
                    LockSupport.park();
                }
            }
    
        }
    
        public static void main(String[] args) throws InterruptedException {
            t1.start();
            Thread.sleep(100);
            t2.start();
            LockSupport.unpark(t1); //即使unpark()发生在park前,程序也能正常执行。
            LockSupport.unpark(t2);
            t1.join();
            t2.join();
        }
    }

    park还支持中断影响,且不抛出异常。

    Simple is important!
  • 相关阅读:
    Aspose.Words三 创建表格
    Aspose.words一 DOM结构
    Aspose.words四 bookmark
    Aspose.Words五 MergeField
    为什么使用Reazor
    C#实现发送给QQ邮件
    T4模板之基础篇
    avalon子孙元素属性监听
    C#设置WebBrowser IE浏览器版本
    【GoLang】GoLang GOPATH 工程管理 最佳实践
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/7459166.html
Copyright © 2020-2023  润新知