创建线程的方法:
继承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.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():用该锁的获得方式,如果线程在获取锁的阶段进入了等待,那么可以中断此线程,先去做别的事