线程(Thread)

发布于:2024-09-18 ⋅ 阅读:(13) ⋅ 点赞:(0)

目录

线程(Thread)

线程的创建方式 实现方式

Runnable和Callable的区别

线程的命名和优先级

线程的六种状态

线程的插队

线程的中断

线程的让出

守护线程

设置线程为守护线程

sleep()和wait()的区别

线程的同步synchronized锁

语法格式

实现原理

锁升级(锁优化、所膨胀)

线程安全的案例

ReentrantLock锁

并发集合

CopyOnWriteArrayList

思想

并发修改时保证线程安全

并发读取

CopyOnWriteArraySet

BlockingQueue阻塞队列

ArrayBlockingQueue:有界队列

LinkedBlockingQueue:无界队列

ConcurrentHashMap

线程池

常用方法

执行流程

配置参数

拒绝策略

常用线程池


线程(Thread)

线程的创建方式 实现方式

创建方式只有一种:通过Thread创建

实现方式有四种分别是:

  1. 继承Thread类实现

  2. 传入Runnable接口实现类实现

  3. 传入Callable接口实现类实现(要用FutureTask转化为runnable)

  4. 通过线程池实现

Runnable和Callable的区别

  1. runnable接口中的run()方法没有返回值,callable接口中的call()方法有返回值

  2. callable接口实现类中的run方法允许异常向上抛出,可以在内部处理,runnable接口实现类中run方法的异常必须在内部处理,不能向上抛出。

线程的命名和优先级

命名

  1. 在实例化Thread时传入线程名

  2. setName()方法设置线程名

优先级:setPriority()方法设置,(最大10,最小1,默认5)

线程的六种状态

线程创建后为new状态,start()启动后进入runnable可运行状态,run()方法执行结束后进入terminated终止状态,runnable有三个分支状态,当多个线程竞争时,没有获取到锁的线程进入blocked阻塞状态。调用Object.wait()方法和Thread.join()方法后会进入waiting等待状态,调用notify()方法唤醒线程重新进入runnable状态。调用Thread.join(时间值)、Object.wait(时间值)、Thread.sleep(时间值)等方法进入timed_waiting计时,等待状态时间结束后恢复runnable可运行状态。

线程的插队

调用 join() 方法实现插队。

底层通过调用Object的wait方法实现,因为线程在die的时候会自动调用自身的notifyAll方法,来释放所有的资源和锁。

线程的中断

interrupt()

修改中断状态为true,抛出InterruptedException,执行结束。

线程的让出

yield() 让出一次

守护线程

设置线程为守护线程

通过 setDaemon(true) 方法设置

守护线程是用来为用户线程服务的,当一个程序中的所有用户线程都结束之后,无论守护线程是否在工作都会跟随用户线程一起结束。

sleep()和wait()的区别

  1. 休眠过程中,当前线程不会让出持有的"锁",等待过程中,当前线程会让出持有的"锁"

线程的同步synchronized锁

线程安全问题:多个线程同时访问竞争一个资源时,会导致数据损坏不一致。

保证一段代码的原子性就是通过加锁和解锁实现的,实现线程的同步安全,参数对象一致则使用同一个锁。

            synchronized (mutex) {
                Counter.count-=1;
            }

synchronized是一个关键字

语法格式

代码块:自定义对象作为锁

普通方法前:this,代表调用该方法的对象

静态方法前:该静态类Class对象

实现原理

1.通过Monitorenter和Monitorexit两个指令实现

2.通过monitor监视器机制实现线程同步

WaitSet:线程等待区

EntryList:线程阻塞区

Owner:线程拥有者

锁升级(锁优化、所膨胀)

在JDK1.6之前,synchronized性能开销较大;在JDK1.6之后,对synchronized进行了优化,它会自动根据程序的执行情况,自动进行锁的升级:偏向锁->轻量级锁->重量级锁

偏向锁(偏斜锁):只有一个线程访问时,使用偏向锁,通过Owner记录线程ID实现

轻量级锁:出现多个线程访问时(没有并发),使用轻量级锁,通过CAS实现

重量级锁:出现多个线程并发访问时,使用重量级锁。由于重量级锁,使用操作系统的互斥锁实现。(使用互斥锁,从“用户态”切换至“内核态”,带来性能开销,所以性能相对较差)

线程安全的案例

可变字符串的线程安全: StringBuffer : 线程安全(在改变字符串内容的方法上使用synchronized同步锁),性能较差

StringBuilder:线程不安全,性能较好

集合类的线程安全(使用synchronized关键字实现线程安全)

List接口的线程安全实现类:Vector,Stack

Map接口的线程安全实现类:Hashtable

ReentrantLock锁

1.ReentrantLock是核心类库提供的锁实现类,实现了Lock接口,通过lock()方法加锁,unlock()方法释放锁。

2.通过trylock()方法支持获取锁的尝试机制

3.支持公平锁和非公平锁,内部通过AQS机制实现

ReentrantLock实现线程安全的案例

CopyOnWriteArrayList

ArrayBlockingQueue

并发集合

List Set Map Queue

CopyOnWriteArrayList

思想

修改时将原数组内容复制Copy到新数组内,在新数组内修改,然后替换

并发修改时保证线程安全

通过ReentrantLock实现多个线程并发修改时的线程安全同步(添加元素的同时,不允许删除)

添加新元素:list.add("")

按照指定下标替换元素:list.set(index, element)

按照指定下标删除元素:list.remove(0)

并发读取

没有加锁,允许多个线程同时并发读取;但是读取时,可能产生脏读(读取的同时,允许写入操作)。

CopyOnWriteArraySet

内部通过一个CopyOnWriteArrayList实现

BlockingQueue阻塞队列

阻塞队列:有两个线程,分别进行读写(task和put)操作;读取时,不允许写入,如果队列为空,则读取线程阻塞;写入时,不允许读取,如果队列已满,则写入线程阻塞;

经常用于生产消费场景

ArrayBlockingQueue:有界队列

LinkedBlockingQueue:无界队列

ConcurrentHashMap

JDK1,7:通过分段锁实现线程安全

JDK1,8:通过 synchronized+CAS实现线程安全

当产生哈希冲突时,通过synchronized将根节点作为锁,进行线程的同步安全

在没有产生哈希冲突时,通过CAS进行无锁化操作,降低synchronized进行线程同步操作所引发的性能下降

线程池

常用类和接口

ExecutorService接口:线程池的操作

Executors类:工具类,提供了常见线程池的封装

ThreadPoolExecutor类:具体线程池实现类

常用方法

void execute(Runnable command):提交线程任务

Future<T> submit(Callable<T> task):提交线程任务,可以获取线程执行结果

void shutdown():将线程池中的线程任务执行完毕后,关闭线程池

List<Runnable> shutdownNow():立刻关闭线程池,并返回未完成的线程任务

执行流程

  1. 提交线程任务,分配空闲线程

  2. 判断“工作线程数”是否超出“核心线程数”,如果未超出,则创建新线程;

  3. 如果超出,将线程任务存入工作队列

  4. 如果工作队列已满,判断判断“工作线程数”是否超出“最大线程数”,如果未超出,则创建新线程

  5. 如果超出,则执行拒绝策略

配置参数

核心线程数

最大线程数

线程存活时间

工作队列

线程工厂

拒绝策略

AbortPolicy(默认拒绝策略):丢弃当前线程任务,并抛出RejectedExecutionException

AbortPolicy:丢弃当前线程任务

DiscardOldestPolicy:丢弃工作队列中最早入队的线程任务

CallerRunsPolicy:由当前调用线程处理执行线程任务

常用线程池

Executors.newFixedThreadPool(3):固定数目的线程池

Executors.newCachedThreadPool():动态数目的线程池(线程被缓存,提供重复使用效率)

Executors.newSingleThreadExecutor():仅包含1个线程的线程池(将大量的线程任务保存至工作队列,然后按照提交顺序,用一条线程依次处理)

Executors.newScheduledThreadPool(5):可以按照时间进行调度执行任务的线程池


网站公告

今日签到

点亮在社区的每一天
去签到