Java 并发编程 (一周学习总结)

线程状态

new --> runnable <---> running --> dead
         |                ^
         |                |
         *---> blocked ---*
         |                |
         |                |
         *---> waiting ---*
         |                |
         |                |
         *-> time waiting *
  • new 创建状态
  • runnable 就绪状态,线程所需资源准备完毕
  • running 运行状态,线程获得处理机时间
  • blocked 阻塞状态,线程被同步阻塞或者I/O阻塞
  • waiting 阻塞状态,线程主动等待
  • time waiting 阻塞状态,线程主动睡眠指定时间
  • dead 消亡状态,线程执行完毕或异常中断

Thread 类

简单例子

创建一个简单线程的例子如下,重写的 run 方法中为线程执行代码,start 方法启动线程。

new Thread() {
    @Override
    public void run() {
        System.out.println("new thread");
    }
}.start();

常用方法

// 线程进入就绪状态
start()
// 线程主动睡眠指定时间
sleep(long millis)
sleep(long millis, int nanoseconds)
// 线程让出处理机时间,给同优先级的线程
// 注意该方法让线程重回就绪状态,而不是阻塞状态
yield()
// 等待线程执行完毕,或者等待指定时间
join()
join(long millis)
join(long millis, int nanoseconds)
// 中断处于阻塞状态的线程,注意不能中断正在运行中的线程
interrupt()
// 获取线程标识符
getID()
// 获取设置线程名称
getName()
setName()
// 获取设置线程优先级
getPriority()
setPriority()
// 设置线程是否为守护线程
setDaemon()
// 判断是否为守护线程
isDaemon()

参考 http://www.importnew.com/26834.html

thread 对比 runnable

参考 https://blog.csdn.net/wwww1988600/article/details/7309070

守护线程

  • setDaemon(true) 必须在 start() 之前设置,否则会抛出 IllegalThreadStateException 异常,且不能将运行的线程设置为守护线程
  • 守护线程中产生的新线程,也是守护线程。
  • 守护线程不要访问固有资源(文件、数据库等),因为线程会随时发生中断,不能保证操作的安全性。

参考 https://www.cnblogs.com/lixuan1998/p/6937986.html

线程池

ThreadPoolExecutor 类

构造函数及其参数

该类有四个构造函数,下面是参数最全的构造函数。

ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                   long keepAliveTime,
                   TimeUnit unit,
                   BlockingQueue<Runnable> workQueue,
                   ThreadFactory threadFactory,
                   RejectedExecutionHandler handler)
  • corePoolSize 核心池大小。创建线程池后,线程池中的线程数为0。当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到 corePoolSize 后,就会把到达的任务放到缓存队列当中。
  • maximumPoolSize 线程池最大线程数,表示在线程池中最多能创建多少个线程。
  • keepAliveTime 线程无任务执行时,最多保持多长时间后终止。只有线程池中的线程数大于 corePoolSize 时,keepAliveTime才会起作用。
  • unit 参数 keepAliveTime 的时间单位,有以下7种取值。
TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒
  • workQueue 存储等待执行任务的阻塞队列。
  • handler 拒绝处理任务时的策略,有以下4种策略。
ThreadPoolExecutor.AbortPolicy  // 丢弃任务,并抛出RejectedExecutionException异常。 
ThreadPoolExecutor.DiscardPolicy   // 丢弃任务,但不抛出异常。 
ThreadPoolExecutor.DiscardOldestPolicy  // 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy  // 由调用线程处理该任务 

常用方法

execute()  // 向线程池提交任务,交由线程池去执行。
submit()  // 向线程池提交任务,与 execute() 方法不同,其能够返回任务执行的结果。
shutdown()  // 关闭线程池
shutdownNow()  // 关闭线程池

静态方法创建线程池

Executors 类中有几个静态方法,可用于创建配置好的线程池。一般没有特别要求时,推荐使用下面的静态方法创建线程池。

newCachedThreadPool()  // 创建容量大小为 Integer.MAX_VALUE 的线程池
newSingleThreadExecutor()  // 创建容量大小为 1 的线程池
newFixedThreadPool(int)  // 创建容量为指定大小的线程池

参考 https://www.cnblogs.com/dolphin0520/p/3932921.html

注意点

  • 线程频繁创建与销毁,会降低执行效率,因而可采用线程池代替。

volatile关键字与synchronize关键字

参考 https://www.cnblogs.com/zhengbin/p/5654805.html

java 锁

参考 https://www.cnblogs.com/wuhan729/p/8601108.html

java内存模型

Java内存模型规定了所有的变量都存储在主内存(Main Memory)中,此外每条线程还有自己的工作内存(Working Memory)。

线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,不能直接读写主内存中的变量。并且,不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值得传递均需要通过主内存来完成,

参考 http://www.cnblogs.com/zhengbin/p/6407137.html

concurrent包

参考 http://www.importnew.com/26461.html

CAS 原理

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该 位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前 值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。

参考 https://www.cnblogs.com/barrywxx/p/8487444.html

参考 https://blog.csdn.net/u011305680/article/details/80187623

future 和 callable

参考 https://www.cnblogs.com/fengsehng/p/6048609.html

https://www.jianshu.com/p/01188fa8e511

猜你喜欢

转载自www.cnblogs.com/linzhehuang/p/10467813.html