Java5的 线程并发库

Wesley13
• 阅读 571

java.util.concurrent.atomic

一个小型工具包,支持单个变量上的无锁线程安全编程. 包含的类: Java5的 线程并发库 这些类的相关操作都是原子性的

java.util.concurrent

  1. 线程池

    //线程池的创建
    //创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程。 
    //在任何时候,最多nThreads个线程同时处理任务。 
    //如果所有线程处于活动状态时又提交其他任务,则它们将在等待队列中直到有一个线程空闲可用。 
    //如果任何线程由于在关闭之前的执行期间发生故障而终止,如果需要执行后续任务,则新线程将占用它。 
    //池中的线程将一直存在,直到调用shutdown方法 。
    //public static ExecutorService newFixedThreadPool(int nThreads)
    ExecutorService es = Executors.newFixedThreadPool(3);
    
    //向线程池中添加任务
    es.execute(new Runnable(){});//可以添加多个任务
    //但是最多有三个线程去执行这些任务,即最多只有三个任务同时执行
    
    //线程池的关闭
    es.shutdown();//所有任务执行完后关闭
    es.shutdownNow(); //立即关闭,不管任务有没有执行完
    
    //创建缓存的线程池
    //创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。 
    //这些池通常会提高执行许多短暂异步任务的程序的性能。 
    //调用execute将重用以前构造的线程(如果可用)。 
    //如果没有可用的线程,将创建一个新的线程并将其添加到该池中。 
    //未使达六十秒的线程将被终止并从缓存中删除。 
    //因此,长时间保持闲置的池将不会消耗任何资源
    public static ExecutorService newCachedThreadPool()
    
    //创建只有单个线程的线程池
    
    public static ExecutorService newSingleThreadExecutor() 
    
    //如何实现线程死掉后重新启动,通过单一线程池,这样这个线程死掉后,线程池会自动重新创建一个线程来替代
    
    //调度线程池
    ScheduledExecutorService se = Executors.newScheduledThreadPool(3);
    se.schedule(new Runnable() //3秒后执行
    {    
        @Override
        public void run()
        {
            System.out.println("bombing");
        }
    }, 3, TimeUnit.SECONDS);
    
    se.scheduleAtFixedRate(new Runnable()//6秒后第一次执行,以后每隔两秒执行一次
    {
    
        @Override
        public void run()
        {
            System.out.println("bombing");
        }
    }, 6, 2, TimeUnit.SECONDS);
    
    se.scheduleWithFixedDelay(new Runnable()
    {
    
        @Override
        public void run()
        {
            System.out.println("bombing");
        }
    }, 3, 2, TimeUnit.SECONDS);
    

Callable 与 Future 类似 dot net 的async与await

使用Callable来执行任务,Future获取结果,在使用到结果的时候如果Callable还没结束,程序会暂停并等待结果,就跟await一样

public class CallableAndFuture
{
    /**
     * @param args
     */
    public static void main(String[] args)
    {
        ExecutorService es = Executors.newSingleThreadExecutor();
        Future<String> future = es.submit(new Callable<String>()
        {
            @Override
            public String call() throws Exception
            {
                Thread.sleep(2000);
                return "Hello";
            }
        });
        
        System.out.println("等待结果");
        try
        {
            System.out.println("返回结果:"+future.get());
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        catch (ExecutionException e)
        {
            e.printStackTrace();
        }
        
        es.shutdown();
        
        ExecutorService es1 = Executors.newFixedThreadPool(10);
        CompletionService<Integer> completionService = new ExecutorCompletionService<>(es1);
        
        for(int i=1;i<=10;i++)
        {
            final int sequence=i;
            completionService.submit(new Callable<Integer>()
            {

                @Override
                public Integer call() throws Exception
                {
                    Thread.sleep(new Random().nextInt(5000));
                    return sequence;
                }
            });
        }
        
        for(int i=0;i<10;i++)
        {
            try
            {
                System.out.println(completionService.take().get());
            }
            catch (InterruptedException | ExecutionException e)
            {
                e.printStackTrace();
            }
        }
        
        
        es1.shutdown();
    }
}

java.util.concurrent.locks

主要的类与接口 Java5的 线程并发库

//Lock接口
void lock() //获得锁。  
void lockInterruptibly() //获取锁定,除非当前线程是 interrupted 。 
Condition newCondition() //返回一个新Condition绑定到该实例Lock实例。
boolean tryLock() //只有在调用时才可以获得锁。  
boolean tryLock(long time, TimeUnit unit) //如果在给定的等待时间内是空闲的,并且当前的线程尚未得到 interrupted,则获取该锁。  
void unlock() //释放锁。 
//使用规范
//当在不同范围内发生锁定和解锁时,
//必须注意确保在锁定时执行的所有代码由try-finally或try-catch保护,以确保在必要时释放锁定。
Lock l = ...; l.lock(); try { } finally { l.unlock(); } 
//ReentrantLock
static class Outputer
{
    Lock lock = new ReentrantLock();
        
    public void output(String name)
    {
        lock.lock();
        try
        {
            int len=name.length();
            for(int i=0;i<len;i++)
            {
                System.out.print(name.charAt(i));
            }
            System.out.println();
        }
        finally
        {
            // TODO: handle finally clause
            lock.unlock();
        }
    }
        
} 

//基于读写锁的缓存
public class CacheDemo
{
    private Map<String, Object> cache = new HashMap<>();
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    public static void main(String[] args)
    {
        
    }
    //这种思路不能很好的处理获取数据
    //因为所有的获取数据都是互斥的,效率低
    public synchronized Object getData1(String key)
    {
        Object value = cache.get(key);
        if(value==null)
        {
            value=new Random().nextInt(100);
            cache.put(key, value);
        }
        return value;
    }
    
    //锁降级:从写锁变成读锁;
    //锁升级:从读锁变成写锁。
    //读锁是可以被多线程共享的,写锁是单线程独占的。
    //也就是说写锁的并发限制比读锁高。
    /**
     * 这种方法使用读写锁来处理缓存,同时读的时候不互斥,
     *当有一个去修改的时候,转换为写锁
     * @param key
     * @return value
     */
    public Object getData2(String key)
    {
        rwl.readLock().lock();
        Object value = null;
        try
        {
            value=cache.get(key);
            if(value==null)//缓存中没有数据,去获取
            {
                rwl.readLock().unlock();//释放读锁
                rwl.writeLock().lock();    //加写锁
                try
                {
                    value=cache.get(key);//为了防止多次写入
                    if(value==null)//为了防止多次写入
                    {
                        value=new Random().nextInt(100);
                        cache.put(key, value);
                    }
                    rwl.readLock().lock();
                }
                finally
                {
                    // TODO: handle finally clause
                    rwl.writeLock().unlock();
                }
                
            }
        }
        finally 
        {
            rwl.readLock().unlock();
        }
        
        return value;
    }
}

/*
    关于读写锁升级和降级的限制
    1.因为同一个线程中,在没有释放读锁的情况下,就去申请写锁,这属于锁升级,ReentrantReadWriteLock是不支持的。
    2.从写锁降级成读锁,并不会自动释放当前线程获取的写锁,仍然需要显示的释放,否则别的线程永远也获取不到写锁。
*/

Condition 线程通信

    //利用condition进行线程间的通信
    static class Business
    {
        private ReentrantLock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
        private Condition condition3 = lock.newCondition();
        private int flag=1;
        public void sub(int i)
        {
            lock.lock();
            try
            {
                while(flag!=1)
                {
                    try
                    {
                        //this.wait();
                        condition1.await();
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }
                for (int j = 1; j <= 10; j++)
                {
                    System.out.println("sub thread sequence of " + j+",loop of "+i);
                }
                flag=2;
                condition2.signal();
            }
            finally
            {
                // TODO: handle finally clause
                lock.unlock();
            }
        }
        
        public void sub2(int i)
        {
            lock.lock();
            try
            {
                while(flag!=2)
                {
                    try
                    {
                        //this.wait();
                        condition2.await();
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }
                for (int j = 1; j <= 20; j++)
                {
                    System.out.println("sub2 thread sequence of " + j+",loop of "+i);
                }
                flag=3;
                condition3.signal();
            }
            finally
            {
                // TODO: handle finally clause
                lock.unlock();
            }
        }
        
        public void main(int i)
        {
            lock.lock();
            try
            {
                while(flag!=3)
                {
                    try
                    {
                        //this.wait();
                        condition3.await();
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }
                for (int j = 1; j <= 100; j++)
                {
                    System.out.println("main thread sequence of " + j+",loop of "+i);
                }
                flag=1;
                //this.notify();
                condition1.signal();
            }
            finally
            {
                // TODO: handle finally clause
                lock.unlock();
            }
            
        }
    }
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
4、jstack查看线程栈信息
1、介绍利用jps、top、jstack命令找到进程中耗时最大的线程,以及线程状态等等,同时最后还可以显示出死锁的线程查找:FoundoneJavaleveldeadlock即可1、jps获得进程号!(https://oscimg.oschina.net/oscnet/da00a309fa6
Wesley13 Wesley13
3年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这