资讯专栏INFORMATION COLUMN

java-实战java高并发程序设计-ch3JDK并发包

fox_soyoung / 1315人阅读

摘要:并发包参考多线程的同步协助同步控制扩展功能重入锁之前重入锁性能好于但开始优化现在二者的性能相差不大。倒计时器的扩展循栅栏。做好异常处理工作。线程池的内部实现该部分待看书

JDK 并发包

参考:> https://github.com/chengbingh...

3.1 多线程的同步协助:同步控制

3.1.1 synchronized 扩展功能:重入锁
jdk1.5之前重入锁ReentrantLook性能好于synchronized, 但jdk1.6 开始优化ReentrantLook, 现在二者的性能相差不大。

/**
 * @author ChengBing Han
 * @date 21:50  2018/6/23
 * @description
 */
public class ReentrantLockTest {
    static ReentrantLock reentrantLock = new ReentrantLock();
    static final Object obj = new Object();
    public static void main(String[] args) throws InterruptedException {

        final Thread t1 = new Thread(new Runnable() {
            public void run() {
                System.out.println("T1 lock1");
                reentrantLock.lock();
                System.out.println("T1 lock2");
                reentrantLock.lock();
                System.out.println("T1 unlock1");

                reentrantLock.unlock();
                System.out.println("T1 unlock2");
                reentrantLock.unlock();
            }
        });


        final Thread t2 = new Thread(new Runnable() {
            public void run() {
                synchronized (obj){
                    System.out.println("t2 lock1");
                    synchronized (obj){
                        System.out.println("t2 lock2 ");

                    }
                }
                System.out.println("t2 end");
            }

        });

        System.out.println("lock============");
        t1.start();
        Thread.sleep(1000);
        System.out.println("syschronized==================");
        t2.start();


    }


}

输出:
lock============
T1 lock1
T1 lock2
T1 unlock1
T1 unlock2
syschronized==================
t2 lock1
t2 lock2 
t2 end

中断响应

public class Interrupted implements Runnable {
    private  Integer state = 0;

    public Interrupted() {
    }

    public Interrupted(Integer state) {
        this.state = state;
    }
   static ReentrantLock reentrantLock1 = new ReentrantLock();
   static ReentrantLock reentrantLock2 = new ReentrantLock();

    public void run() {

        try {
            if(state == 1) {
                reentrantLock1.lockInterruptibly();
                System.out.println("state1===lock1");
                Thread.sleep(1000);
                reentrantLock2.lockInterruptibly();
                System.out.println("state1===lock2");

            }else if(state == 2){
                reentrantLock2.lockInterruptibly();
                System.out.println("state2===lock2");
                Thread.sleep(1000);

                reentrantLock1.lockInterruptibly();
                System.out.println("state2===lock1");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            if(reentrantLock1.isHeldByCurrentThread()){
                reentrantLock1.unlock();
            }
            if(reentrantLock2.isHeldByCurrentThread()){
                reentrantLock2.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final Interrupted r1 = new Interrupted(1);
        final Interrupted r2 = new Interrupted(2);
        final Thread t1 = new Thread(r1);
        final Thread t2 = new Thread(r2);

        t1.start();
        Thread.sleep(100);
        t2.start();
        Thread.sleep(5000);

        t2.interrupt();
    }
}
输出
state1===lock1
state2===lock2
java.lang.InterruptedException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
    at com.hcb.thread.c3_1_retrantlookinterrupted.Interrupted.run(Interrupted.java:39)
    at java.lang.Thread.run(Thread.java:748)
state1===lock2

锁申请等待限时
一个锁只能锁住某个时间段

public class TimeLock implements Runnable{

    static ReentrantLock reentrantLock = new ReentrantLock();
    public void run() {

        try {
            if(reentrantLock.tryLock(3, TimeUnit.SECONDS)){
                System.out.println(Thread.currentThread().getName() + " run");
                Thread.sleep(6000);

            }else {
                System.out.println(Thread.currentThread().getName() + "getLock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //注意finally 这里释放锁的方式
            if(reentrantLock.isHeldByCurrentThread()){
                reentrantLock.unlock();
            }
        }


    }
    
    public static void main(String[] args) throws InterruptedException {
        final TimeLock r1 = new TimeLock();

        final Thread thread1 = new Thread(r1);
        thread1.setName("t1");
        thread1.start();
        Thread.sleep(100);

        final TimeLock r2 = new TimeLock();
        final Thread thread2 = new Thread(r2);
        thread2.setName("t2");
        thread2.start();

    }
}

公平锁

public class FairLock {

    //构造函数为true,表示公平
    static ReentrantLock reentrantLock = new ReentrantLock(true);
    
    public static class ThreadFair implements Runnable {
        public void run() {
            while (true) {
                try {
                    reentrantLock.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName() + "  run  ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    if (reentrantLock.isHeldByCurrentThread()) {
                        reentrantLock.unlock();
                    }
                }
            }

        }
    }

    public static void main(String[] args) {
       
            final ThreadFair threadFair = new ThreadFair();
            final Thread fairThread1 = new Thread(threadFair, "fairThread1");
            final ThreadFair threadFair2 = new ThreadFair();
            final Thread fairThread2 = new Thread(threadFair2, "fairThread2");

            fairThread1.start();
            fairThread2.start();
            

    }

}

output:
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  

重入锁的condition条件

Condition条件类似与wait,notify方法
备注:Condition的使用注意
1、必须在lock.lock()
和lock.singXX中使用 await/singXX

2、方法名是await 不是wait,wait 是object的方法

public class ConditionLock {
    static ReentrantLock reentrantLock = new ReentrantLock();
    static Condition condition = reentrantLock.newCondition();


    static class ConditionLockThread implements Runnable {

        public void run() {

            reentrantLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " wait...");
                //方法是await不是object的wait
                condition.await();
                System.out.println(Thread.currentThread().getName() + " end wait...");


            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                if(reentrantLock.isHeldByCurrentThread()){
                    reentrantLock.unlock();
                }

            }

        }
    }

    public static void main(String[] args) throws InterruptedException {
        final ConditionLockThread conditionLockThread1 = new ConditionLockThread();
        final Thread thread1 = new Thread(conditionLockThread1, "ConditionLockThread1");

        final ConditionLockThread conditionLockThread2 = new ConditionLockThread();
        final Thread thread2 = new Thread(conditionLockThread2, "ConditionLockThread2");

        thread1.start();

        thread2.start();
        Thread.sleep(1000);
        //必须在 lock.lock/unlock 中间使用
        reentrantLock.lock();
        condition.signalAll();
        reentrantLock.unlock();

    }
}


允许多个线程同时访问 信号量Semaphore
可以允许n个线程同时访问,结合公平锁。

3.1.4 读写锁
ReadWriteLock JDK

/**
 * @author ChengBing Han
 * @date 14:44  2018/7/7
 * @description
 */
public class ReadWriteLockDemo {
    public static ReentrantLock lock = new ReentrantLock();
    private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    public static Lock readLock = reentrantReadWriteLock.readLock();
    public static Lock writeLock = reentrantReadWriteLock.writeLock();
    public static int value;

    private static int index = 0;

    public static Object handleRead(Lock lock) {

        lock.lock();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        System.out.println("read value is " + value);
        return value;
    }

    public static void handleWrite(Lock lock, int newValue) {
        lock.lock();

        try {
            Thread.sleep(1000);
            value = newValue;
            System.out.println("write value is " + value);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) {


        final long startTime = System.currentTimeMillis();


        final Runnable readRunnable = new Runnable() {
            public void run() {
                handleRead(readLock);
            }
        };


        final Runnable writeRunnable = new Runnable() {
            public void run() {

                handleWrite(writeLock, ++index);
            }
        };

        for (int i = 0; i < 10; i++) {
            final Thread thread = new Thread(readRunnable);
            thread.start();
        }

        for (int i = 0; i < 10; i++) {
            final Thread thread = new Thread(writeRunnable);
            thread.start();

        }

        //为什么要在while中输出一些东西呢
        //如果还是一个空的While循环,while 会被优化在-Server模式下
        while (value != 10){
            System.out.print("");
        }

        final long end = System.currentTimeMillis();
        System.out.println("app use :" + (end - startTime)/1000);

    }
}

倒计时(线程个数)器: CountDownLatch
可以让n线程都完成任务了,在继续执行某个主线程。例如,火箭发射前有10个检查任务,这时创建10个线程分别处理十个任务,再创建一个发射火箭的线程,每次完成一个检查任务,CountDownLatch 记录一个,这样,可以等10个都完成了,发射火箭的线程再执行。

倒计时器的扩展:循栅栏。
扩展了CountDownLatch,将军让10个士兵为1组, 这样一组的完成类似于CountDownLatch, 如果与多组就用循环栅栏。 可以循环多组。

线程阻塞工具类:LockSupport
提供一些阻塞的功能

3.2 线程复用:线程池

3.2.1什么是线程池
同数据库连接池
3.3.2不要重复造轮子:jdk对线程池的支持

Executors 是什么?
一言蔽之:工厂

Executors的介绍:
/**
 * Factory and utility methods for {@link Executor}, {@link
 * ExecutorService}, {@link ScheduledExecutorService}, {@link
 * ThreadFactory}, and {@link Callable} classes defined in this
 * package. This class supports the following kinds of methods:
 *
 * 
    *
  • Methods that create and return an {@link ExecutorService} * set up with commonly useful configuration settings. *
  • Methods that create and return a {@link ScheduledExecutorService} * set up with commonly useful configuration settings. *
  • Methods that create and return a "wrapped" ExecutorService, that * disables reconfiguration by making implementation-specific methods * inaccessible. *
  • Methods that create and return a {@link ThreadFactory} * that sets newly created threads to a known state. *
  • Methods that create and return a {@link Callable} * out of other closure-like forms, so they can be used * in execution methods requiring {@code Callable}. *
* * @since 1.5 * @author Doug Lea */

线程池说明

固定数量的线程池
弊端:如果线程池中有5个任务,第一个任务

/**
 * @author ChengBing Han
 * @date 12:19  2018/7/14
 * @description
 */
public class FixThreadPoolTest {
    
    public static class MyTask implements Runnable{
        public void run() {
            final long id = Thread.currentThread().getId();
            System.out.println("当前线程的id是: "  + id);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    
    public static void main(String[] args) {
        final ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            newFixedThreadPool.submit(new MyTask());
        }
    }
}
通过输出可以看到,10个任务,用池子中的了5个线程
**output:**
当前线程的id是: 13
当前线程的id是: 15
当前线程的id是: 16
当前线程的id是: 13
当前线程的id是: 14
当前线程的id是: 17
当前线程的id是: 15
当前线程的id是: 16
当前线程的id是: 13
当前线程的id是: 14

异常处理

/**
 * @author ChengBing Han
 * @date 12:19  2018/7/14
 * @description
 */
public class FixThreadPoolTest {

    static boolean flag = true;
    
    public static class MyTask implements Runnable{
        public void run() {
            if(flag){
                flag=false;
                System.out.println("出现异常");
                System.out.println(1/0);
                System.out.println("异常结束");
            }

            final long id = Thread.currentThread().getId();
            System.out.println("当前线程的id是: "  + id);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) {
        final ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            newFixedThreadPool.submit(new MyTask());
        }
        newFixedThreadPool.shutdown();
    }
}


output:
出现异常
当前线程的id是: 11
当前线程的id是: 14
当前线程的id是: 15
当前线程的id是: 13
当前线程的id是: 12
当前线程的id是: 14
当前线程的id是: 15
当前线程的id是: 11
当前线程的id是: 13

**结论:根据上述输出,可以发现,线程次中有10次调用,某次发生异常,不会影响其它的9次**

定时线程:

/**
 * @author ChengBing Han
 * @date 12:24  2018/7/14
 * @description
 */
public class SheduleThreadPoolTest {
    
    public static class MyTask implements Runnable{

        public void run() {
            System.out.println("Thread is run which  id is : " + Thread.currentThread().getId());
        }
    }

    public static void main(String[] args) {
        final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
        scheduledExecutorService.scheduleAtFixedRate(new MyTask(),10,1,TimeUnit.SECONDS);
    }
}

*注意定时的这个线程池和上述的newFixedThreadPool不同,一旦某个任务出现调度异常,那么后面的任务都不会再执行。==》做好异常处理工作。

*定时任务的两个方法不同之处在于
scheduleAtFixedRate: 每隔2秒调度一个任务,但是一个任务的时间是8秒(大于2秒)那么实际是8秒调度一个任务。
scheduleWithFixedDelay: 隔2秒调度一个任务,但是一个任务的时间是8秒(大于2秒)那么实际是8+2秒调度一个任务。

3.2.3 线程池的内部实现:
该部分待看书

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/71348.html

相关文章

  • 实战Java程序设计6】挑战无锁算法

    摘要:在本例中,讲述的无锁来自于并发包我们将这个无锁的称为。在这里,我们使用二维数组来表示的内部存储,如下变量存放所有的内部元素。为什么使用二维数组去实现一个一维的呢这是为了将来进行动态扩展时可以更加方便。 我们已经比较完整得介绍了有关无锁的概念和使用方法。相对于有锁的方法,使用无锁的方式编程更加考验一个程序员的耐心和智力。但是,无锁带来的好处也是显而易见的,第一,在高并发的情况下,它比有锁...

    zengdongbao 评论0 收藏0
  • 聊聊面试中关于问题的应对方案

    摘要:这里呢,我直接给出高并发场景通常都会考虑的一些解决思路和手段结尾如何有效的准备面试中并发类问题,我已经给出我的理解。 showImg(https://segmentfault.com/img/bV7Viy?w=550&h=405); 主题 又到面试季了,从群里,看到许多同学分享了自己的面试题目,我也抽空在网上搜索了一些许多公司使用的面试题,目前校招和社招的面试题基本都集中在几个大方向上...

    xzavier 评论0 收藏0
  • 【转】成为Java顶尖程序员 ,看这10本书就够了

    摘要:实战高并发程序设计这本书是目前点评推荐比较多的书,其特色是案例小,好实践代码有场景,实用。想要学习多线程的朋友,这本书是我大力推荐的,我的个人博客里面二十多篇的多线程博文都是基于此书,并且在这本书的基础上进行提炼和总结而写出来的。 学习的最好途径就是看书,这是我自己学习并且小有了一定的积累之后的第一体会。个人认为看书有两点好处:showImg(/img/bVr5S5);  1.能出版出...

    DTeam 评论0 收藏0
  • [Java-10] ReadWriteLock:快速实现一个完备的缓存

    摘要:此时线程和会再有一个线程能够获取写锁,假设是,如果不采用再次验证的方式,此时会再次查询数据库。而实际上线程已经把缓存的值设置好了,完全没有必要再次查询数据库。 大家知道了Java中使用管程同步原语,理论上可以解决所有的并发问题。那 Java SDK 并发包里为什么还有很多其他的工具类呢?原因很简单:分场景优化性能,提升易用性 今天我们就介绍一种非常普遍的并发场景:读多写少场景。实际工作...

    nevermind 评论0 收藏0
  • 跳槽季如何快速全面复习面试题

    摘要:排序算法和集合工具类排序算法和集合工具类。面试官总是问排序算法也不是在难为你,而是在考察你的编程功底。你首先要理解多线程不仅仅是和那么简单,整个并发包下面的工具都是在为多线程服务。 去年的这个时候楼主通过两个月的复习拿到了阿里巴巴的 offer,有一些运气,也有一些心得,借着跳槽季来临特此分享出来。简单梳理一下我的复习思路,同时也希望和大家一起交流讨论,一起学习,如果不对之处欢迎指正一...

    keke 评论0 收藏0

发表评论

0条评论

fox_soyoung

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<