多线程

本文介绍了Java中实现多线程的三种方式:继承Thread类、实现Runnable接口和使用FutureTask。讨论了线程同步的重要性以及避免上下文切换的策略,包括无锁并发编程、CAS算法和减少线程数量。还详细讲解了不同类型的线程同步方法,如volatile、synchronized同步方法和代码块、重入锁ReentrantLock以及ThreadLocal的使用。同时,提到了死锁的避免策略以及相关工具的使用,如Lmbench、vmstat和jstack。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.实现多线程的三种方式:
①继承Thread类
②实现runnable接口
③通过futureTask包装器来创建Thread线程

特点:可以返回值

public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V> {
使用Callable方式,需要Futertask的支持

    public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable

注意:

并行不一定比串行快:
因为线程有创建上下文切换的开销

 

并发编程可以用到的小工具:

使用:

Lmbench可以测量上下文切换的时长
vmstat 可以测量上下文切换的次数
jstack 命令dump线程信息

怎么减少上下文切换:

1、无锁并发编程
2、CAS算法
3、使用最少线程和使用协程

死锁:

避免死锁的几种常见方法:
1、避免一个线程同时获取多个锁
2、避免一个线程在锁内同时占用多个资源
3、尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
4、对于数据库锁,加锁和解锁必须在一个数据库连接里,负责会出现解锁失败的情况。
 

同步实现方式:

1.volatile:是轻量级的synchronized,在多处理器开发中保证了共享变量的“可见性”。
可见性:当一个线程修改一个共享变量时,另外一个线程可以读到这个修改的值。
它比syncheonized的使用和执行成本更低,因为它不会引起线程调度和上下文切换和调度

cpu术语定义:

内存屏障:是一组处理指令,用于实现对内存操作的顺序限制
缓冲行:缓冲中可以分配的最小存储单位。处理器填写缓冲线时会加载整个缓冲线,需要使用多个主内存读周期
原子操作:不可中断的一个或者一系列操作
缓冲行填充:当处理器识别到从内存中读取操作数是可缓冲的,处理器读取整个缓冲行到适当的缓冲
缓冲命中:如果进行高速缓冲进行填充操作的内存位置仍然是下次处理器访问的地址时,处理器从缓存中读取操作数而不是从内存中读取。
写命中:当处理器操作数写回到一个内存缓存区域时,它首先会检查这个缓存的内存地址是否在缓存行中,如果
存在一个有效的缓存行,则处理器将这个操作数写回到缓存,而不是写回到内存,这个操作被称为写命中。
写缺失:一个有效的缓存行被写入到不存在的内存区域

 

2. 同步方法 

    即有synchronized关键字修饰的方法。     由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 

    内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

3.同步代码块 

    即有synchronized关键字修饰的语句块。     被该关键字修饰的语句块会自动被加上内置锁,从而实现同步     代码如:     synchronized(object){     }     注:同步是一种高开销的操作,因此应该尽量减少同步的内容。 

    通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。 

4.使用重入锁实现线程同步

    在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
     ReenreantLock类的常用方法有:
         ReentrantLock() : 创建一个ReentrantLock实例 
         lock() : 获得锁 
         unlock() : 释放锁 
    注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用 

 

5.使用ThreadLocal

如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

    ThreadLocal 类的常用方法

     ThreadLocal() : 创建一个线程本地变量     get() : 返回此线程局部变量的当前线程副本中的值     initialValue() : 返回此线程局部变量的当前线程的"初始值"     set(T value) : 将此线程局部变量的当前线程副本中的值设置为value

 

注:ThreadLocal与同步机制         a.ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题。 

        b.前者采用以"空间换时间"的方法,后者采用以"时间换空间"的方式 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值