多线程+线程池,锁

  • Post author:
  • Post category:其他


创建线程的方法:

继承Thread 类

Thread 类本质上是实现了Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread 类的start()实例方法。start()方法是一个native 方法,它将启动一个新线程,并执行run()方法。

实现Runnable 接口

如果自己的类已经extends 另一个类,就无法直接extends Thread,此时,可以实现一个Runnable 接口;

启动线程需要实例化一个Thread,并传入实现runnable的实例,调用thread.start(),thread的run方法会调用target.run();

实现Callable 接口

        Callable<Integer> callableObj = () -> {
            int result = integers.stream().mapToInt(i ->i.intValue()).sum();
            return result;
        };
        ExecutorService service =  Executors.newSingleThreadExecutor();
        Future<Integer> future = service.submit(callableObj);
        Integer result=0;
        result = future.get();

通过线程池方法

线程池工作顺序

线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列 里面有任务,线程池也不会马上执行它们。

1.当线程数小于核心线程数时,会一直创建线程直到线程数等于核心线程数;

  1. 当线程数等于核心线程数时,新加入的任务会被放到任务队列等待执行;

  2. 当任务队列已满,又有新的任务时,会创建线程直到线程数量等于最大线程数;

  3. 当线程数等于最大线程数,且任务队列已满时,新加入任务会被拒绝。

线程池核心参数

1.corePoolSize(核心线程数) (1)核心线程会一直存在,即使没有任务执行; (2)当线程数小于核心线程数的时候,即使有空闲线程,也会一直创建线程直到达到核心 线程数; (3)设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭。

2.queueCapacity(任务队列容量) 也叫阻塞队列,当核心线程都在运行,此时再有任务进来,会进入任务队列,排队等待线程 执行。

3.maxPoolSize(最大线程数) (1)线程池里允许存在的最大线程数量; (2)当任务队列已满,且线程数量大于等于核心线程数时,会创建新的线程执行任务; (3)线程池里允许存在的最大线程数量。当任务队列已满,且线程数量大于等于核心线程 数时,会创建新的线程执行任务。

4.keepAliveTime(线程空闲时间) (1)当线程空闲时间达到keepAliveTime 时,线程会退出(关闭),直到线程数等于核心线 程数; (2)如果设置了allowCoreThreadTimeout=true,则线程会退出直到线程数等于零。

allowCoreThreadTimeout(允许核心线程超时,空闲超时则关闭) rejectedExecutionHandler(任务拒绝处理器)


悲观锁

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候 都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使 用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到 了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁

乐观锁

总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但 是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和 CAS 算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量;

详解synchronized与Lock的区别与使用

Java语言直接提供了

synchronized

关键字用于加锁,但这种锁一是很重,线程独占锁,被占时其他线程只能等待释放,没有额外的尝试机制,浪费资源;



ReentrantLock

是Java代码实现的锁,我们就必须先获取锁,然后在

finally

中正确释放锁;

Lock是可重入锁,它和

synchronized

一样,一个线程可以多次获取同一个锁。和

synchronized

不同的是,

ReentrantLock

可以尝试获取锁;

public class Counter {
    private final Lock lock = new ReentrantLock();
    private int count;
​
    public void add(int n) {
        lock.lock();
        try {
            count += n;
        } finally {
            lock.unlock();
        }
    }
    public void del(int n) {
    if(lock.tryLock()){
            try {
                System.out.println("线程名"+thread.getName() + "获得了锁");
            }catch(Exception e){
                e.printStackTrace();
            } finally {
                System.out.println("线程名"+thread.getName() + "释放了锁");
                lock.unlock();
            }
        }else{
            System.out.println("我是"+Thread.currentThread().getName()+"有人占着锁,我就不要啦");
        }
    }
}
lock():获取锁,如果锁被暂用则一直等待
​
unlock():释放锁
​
tryLock(): 注意返回类型是boolean,如果获取锁的时候锁被占用就返回false,否则返回true
​
tryLock(long time, TimeUnit unit):比起tryLock()就是给了一个时间期限,保证等待参数时间
​
lockInterruptibly():用该锁的获得方式,如果线程在获取锁的阶段进入了等待,那么可以中断此线程,先去做别的事



版权声明:本文为qq_42728113原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。