Java多线程

进程与线程

  • 进程:进程是操作系统资源分配的单位 例:I/O资源,内存资源...
  • 线程:线程是资源调度的单位,真正执行的指令  例:操作数据的执行流

线程的创建

三种方法:继承Thread类、实现Runnable接口、实现Callable接口

线程的方法介绍

Thread类常用操作线程方法:

  1. start() :启动线程,使线程进入可运行状态。
  2. run() :包含线程要执行的具体逻辑代码。
  3. sleep(long millis) :使当前线程暂停指定的毫秒数。
  4. yield() :提示线程调度器当前线程愿意让出 CPU 资源,让其他具有相同优先级的线程有机会执行。
  5. join() :等待调用该方法的线程结束。
  6. isAlive() :判断线程是否处于活动状态。
  7. getPriority() :获取线程的优先级。
  8. setPriority(int newPriority) :设置线程的优先级。

如果有两个线程 Thread1 和 Thread2 , Thread1 想要等待 Thread2 执行结束后再继续执行,可以这样写:

Thread thread2 = new Thread(() -> {
    // 线程 2 的执行逻辑
});
thread2.start();
thread2.join(); 
// 这里 Thread1 会等待 thread2 结束后再继续

设置线程的优先级:

Thread thread = new Thread(() -> {
    // 线程执行逻辑
});
thread.setPriority(Thread.MAX_PRIORITY);  // 设置为最高优先级
thread.start();

Volatile关键字

volatile 关键字在 Java 中是一个类型修饰符,用于提供线程之间的可见性和禁止指令重排序。

  • 线程可见性:当一个变量被声明为 volatile 时,意味着对该变量的修改会立即被写入主内存,并且对其他线程是可见的。没有 volatile 修饰时,线程可能会从本地缓存中读取变量值,导致不同线程看到的变量值不一致。
  • 禁止指令重排序:编译器和处理器为了优化性能,可能会对代码的执行顺序进行重排序。但对于 volatile 变量的读写操作,不会与之前和之后的内存操作重排序。

在多线程环境下共享一个标志变量:

volatile boolean flag = false;

// 线程 1
public void setFlag() {
    flag = true;
}

// 线程 2
public void checkFlag() {
    if (flag) {
        // 执行相应操作
    }
}

如果 flag 没有使用 volatile 修饰,线程 2 可能无法及时看到线程 1 对 flag 的修改。需要注意的是,volatile 并不能保证原子性。例如,对于 volatile int count = 0; ,如果多个线程同时执行 count++ 操作,仍然可能会出现数据不一致的问题。在这种情况下,需要使用同步机制(如锁)来保证操作的原子性。

Synchronized关键字

synchronized 关键字在 Java 中用于实现线程同步,确保在同一时刻只有一个线程可以执行被 synchronized 修饰的代码块或方法。

(1)修饰方法

  • 当 synchronized 修饰一个实例方法时,锁定的是当前实例对象(this)。
  • 修饰一个静态方法时,锁定的是当前类的 Class 对象。

(2)修饰代码块

  • 可以指定一个对象作为锁,常见的是 this 或者自定义的一个对象。
public class SynchronizedExample {
    private int count = 0;

    // 实例方法同步
    public synchronized void increment() {
        count++;
    }

    // 静态方法同步
    public static synchronized void staticMethod() {
        // 静态同步方法的逻辑
    }

    public void codeBlockSync() {
        synchronized (this) {
            // 同步代码块的逻辑
        }
    }
}

synchronized 主要作用:

  • 保证线程安全:避免多个线程同时访问和修改共享数据时导致的数据不一致和错误。

  • 解决竞态条件:防止多个线程竞争资源时出现不可预测的结果。

过度使用 synchronized 可能会导致性能下降,因为它会阻塞其他线程的执行。在实际应用中,需要根据具体的业务场景和性能要求,合理地使用 synchronized 或者选择其他更轻量级的同步机制(如 Lock 接口的实现类)。

线程安全其他机制:

  1. final 关键字:当一个变量被声明为 final 时,一旦被初始化,其值就不能被修改。对于引用类型的 final 变量,不能重新指向新的对象,但对象的内容可以修改(如果对象本身不是不可变的)。

  2. Atomic 类:如 AtomicInteger 、 AtomicLong 等,提供了原子性的操作,例如自增、自减等,无需使用同步机制就能保证线程安全。

  3. Lock 接口及其实现类:如 ReentrantLock ,比 synchronized 更加灵活,可以实现更复杂的锁控制逻辑,例如尝试获取锁、限时获取锁等。

  4. ThreadLocal为每个线程提供独立的变量副本,线程之间互不干扰,从而避免了多线程对共享变量的并发访问问题。

  5. 并发容器:如 ConcurrentHashMap 、 ConcurrentLinkedQueue 等,这些容器在并发环境下进行操作时是线程安全的。

`final` 关键字修饰的变量可以被 `volatile` 修饰吗?
  • final 关键字修饰的变量可以被 volatile 修饰,但这种情况相对较少见。通常情况下,如果一个变量是 final ,其不可更改的特性已经能够满足大部分需求,不太需要再用 volatile 修饰。
  • final 修饰的变量一旦被初始化赋值,就不能再被修改其引用(对于引用类型)或值(对于基本数据类型)。
  • volatile 主要用于保证变量的可见性和禁止指令重排序。
  • 当一个 final 变量同时被 volatile 修饰时,它不仅具有不可更改性,还具有更强的线程可见性保证和禁止指令重排序的特性。
使用 AtomicInteger 实现线程安全的计数器:
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicCounterExample {
    private AtomicInteger counter = new AtomicInteger();

    public void increment() {
        counter.incrementAndGet();
    }

    public int getCount() {
        return counter.get();
    }

    public static void main(String[] args) {
        AtomicCounterExample example = new AtomicCounterExample();
        // 多个线程操作
    }
}
使用 ReentrantLock 实现同步:
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int count = 0;
    private ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        LockExample example = new LockExample();
        // 多个线程操作
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值