解析Java的并发编程技术与陷阱

news/2024/11/24 2:54:57/

Java的并发编程技术与陷阱

随着计算机处理器芯片的发展,多核处理器已成为当今计算机的主流配置之一。Java语言作为企业级应用程序开发的主流语言,也在不断地发展与创新,以适应多核处理器的需求。在这种背景下,Java的并发编程技术越来越受到开发者的关注。

然而,对于并发编程技术的理解,往往需要深入了解Java多线程编程原理,才能真正洞察能够合理运用并发编程技术。本文将深入解析Java的并发编程技术与陷阱,从Java多线程的基础知识、线程安全性、锁原理、线程池的实现机制等多个方面进行了详细的介绍,以帮助读者更好的应用Java的并发编程技术,从而提高程序的性能与效率。

一、Java多线程的基础概念与实现机制

Java多线程的基础概念

在操作系统中,进程是系统进行资源分配和调用的基本单位,而线程是进程中的实际执行单位。Java语言通过Thread类来描述线程,Thread类是Java中直接支持线程的类。

Java中线程的创建

Java中有两种方式可以创建线程:

1. 继承Thread类并重写其run()方法

2. 实现Runnable接口并重写其run()方法

实现Runnable接口比继承Thread类更具有优越性,因为Java不支持多重继承,而实现接口可以解决这个问题。因此,在Java中使用Runnable接口比直接继承Thread类通常更可取。

Java多线程的状态转换

线程在Java中有以下几种状态:

1. 新建状态:当线程对象被创建后,线程就处于新建状态。此时,线程没有进入运行状态,也不参与CPU的调度。

2. 就绪状态:当调用线程的start()方法后,线程进入就绪状态,此时线程已经进入了JVM中的就绪队列,等待系统为其分配CPU资源。

3. 运行状态:当CPU调度到一个就绪状态的线程时,线程便进入运行状态,开始执行run()方法。此时,线程使用CPU资源完成各种操作。

4. 阻塞状态:当线程被阻塞时,线程进入了阻塞状态。线程阻塞的原因有多种,例如线程执行sleep(),wait()方法等。此时线程会放弃CPU资源,不参与CPU的调度。

5. 终止状态:线程执行完毕后或出现异常,线程会进入终止状态。此时,线程将不再参与CPU的调度。

二、线程安全性实现方法

线程安全性的定义

简单来说,线程安全就是指多个线程在访问同一共享资源时,要保证对共享资源的数据访问能够正确地进行,不会产生数据不一致性、死锁等问题。

线程安全性实现方法

1. 使用锁机制

Java提供了锁机制(synchronized)来保证线程安全。锁机制是一种同步机制,用于保护共享资源,实现方式分为两种:

1.1 基于对象的锁机制

对于这种锁机制,需要在访问共享资源的方法或代码块上添加synchronized关键字,即使用synchronized关键字来保证并发时,只有一个线程可以访问共享资源。例如:

```java
public synchronized int getCount() {
    return count;
}
```

1.2 基于类的锁机制

对于这种锁机制,需要采用类级别的锁来保护共享资源,也就是使用static synchronized关键字。例如:

```java
public static synchronized void incrCount() {
    count++;
}
```

2. 使用volatile关键字

volatile关键字可以用于保证数据的可见性和顺序性,即保证一个线程在读取一个volatile变量时,能够读到其他线程对该变量的更新。

volatile关键字主要应用于以下两种场景:

2.1 状态标记量

当一个对象的状态标记量需要多个线程共同操作时,可以采用volatile关键字来保证状态标记量的可见性。例如:

```java
volatile boolean flag = false;

public void setFlag(boolean flag) {
    this.flag = flag;
    // ...
}

public void doSomethig() {
    while (!flag) {
        // waiting for flag to be true
    }
    // ...
}
```

2.2 单例模式中的双重检查锁定

在Java中,单例模式是一个经典的设计模式。为了保证线程安全,可以采用双重检查锁定来实现单例模式。双重检查锁定的实现方式是懒汉式单例模式的升级版。在双重检查锁定中,我们需要将单例对象定义为volatile类型,以保证多线程环境下该对象的可见性。例如:

```java
public class Singleton {
    private volatile static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
```

3. 使用原子类

除了锁和volatile关键字,Java还提供了Atomic类来解决非阻塞同步问题。Atomic类是一种轻量级同步机制,它可以用于保证单个变量的读、写和更新操作的原子性。它的更新操作不会引起线程阻塞,即文件不会出现deadlock。

常用的Atomic类有:

3.1 AtomicInteger

AtomicInteger是一种可以保证原子性的Integer。AtomicInteger中提供了多种方法,如get()、getAndIncrement()、decrementAndGet()等,可以保证对该变量的操作具有原子性。例如:

```java
AtomicInteger count = new AtomicInteger(0);

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

public void incrCount() {
    count.incrementAndGet();
}
```

3.2 AtomicReference

AtomicReference是一种原子引用类型,使用它可以保证引用对象的原子性。例如:

```java
AtomicReference<String> ref = new AtomicReference<>("default");

public void setRef(String value) {
    ref.set(value);
}

public boolean compareAndSetRef(String expected, String update) {
    return ref.compareAndSet(expected, update);
}
```

三、锁的实现原理

Java中的锁分为可重入锁、公平锁和非公平锁等类型。不同类型的锁实现机制不同,下面以可重入锁为例,介绍锁的实现原理:

1. 可重入锁

可重入锁即为一个线程可以获取它已经持有的锁,而不会出现死锁的情况。

Java中可重入锁支持两种实现方式:

1.1 synchronized关键字

synchronized关键字的可重入性是由JVM中的monitor来实现的。每个Object对象都有一个monitor,该monitor中包含一个计数器。当一个线程获取了该对象的锁时,monitor的计数值为1,当该线程再次获取该对象的锁时,计数器加1,当该线程释放该对象锁时,计数器减1,如果计数器为0,锁被完全释放。在该过程中,一个线程可以多次获取锁,并且只有持有该锁的线程可以释放该锁。例如:

```java
public synchronized void methodA() {
    // code
    methodB();
    // code
}

public synchronized void methodB() {
    // code
}
```

在例子中,methodA()和methodB()中都使用了synchronized关键字,并且都是同步到该对象上,因此当methodA()执行时,它会获得该对象的锁,同时methodB()也会得到该对象的锁,因此,methodB()的执行不会导致系统死锁。

1.2 ReentrantLock

ReentrantLock是Java提供的可重入锁。与synchronized关键字相比,ReentrantLock具有高度的灵活性,它支持可超时的尝试获得锁、中断线程等高级功能。

ReentrantLock的实现方式主要是AQS(AbstractQueuedSynchronizer)的实现。AQS主要采用了一种先进先出的队列,即FIFO队列来管理线程,它的原理就是当一个线程获取锁时,如果锁已经被其他线程所持有,那么该线程就会被放入等待队列中,等待锁的释放。当锁释放后,等待队列中的第一个线程就会被唤醒,获取到锁并执行相应的操作。

ReentrantLock使用示例:

```java
ReentrantLock lock = new ReentrantLock();

public void methodA() {
    lock.lock();
    try {
        // code
        methodB();
        // code
    } finally {
        lock.unlock();
    }
}

public void methodB() {
    lock.lock();
    try {
        // code
    } finally {
        lock.unlock();
    }
}
```

在例子中,我们使用ReentrantLock来保证线程安全。在执行methodA()方法时,第一次获取锁成功,然后又调用了methodB()方法,也获取到了锁,而在各自方法执行完毕后,都正确地释放了锁。

四、线程池的实现与使用

线程池的好处

线程池可以帮助我们更好地管理线程资源,它可以缩短线程的创建和销毁时间,避免频繁的创建和销毁线程带来的性能开销,并实现线程的复用,提高程序的运行效率。

Java中的线程池常用的有以下三种:

1. FixedThreadPool

FixedThreadPool是一种固定大小的线程池,它管理了一个固定大小的线程池,每当提交一个任务时,就会创建一个线程来执行该任务。并且在线程未执行完毕之前,其他任务将会被阻塞。例如:

```java
ExecutorService executor = Executors.newFixedThreadPool(4);

public void submitTask() {
    executor.submit(() -> {
        // code
    });
}
```

2. CachedThreadPool

CachedThreadPool是一种不固定大小的线程池,它的线程数会根据当前工作负载动态的增加和收缩,避免线程的浪费。例如:

```java
ExecutorService executor = Executors.newCachedThreadPool();

public void submitTask() {
    executor.submit(() -> {
        // code
    });
}
```

3. ScheduledThreadPool

ScheduledThreadPool是一种定时任务线程


http://www.ppmy.cn/news/305466.html

相关文章

Baumer工业相机堡盟工业相机如何使用BGAPISDK控制相机数据流的开启和关闭(C++)

Baumer工业相机堡盟工业相机如何使用BGAPISDK控制相机数据流的开启和关闭&#xff08;C&#xff09; Baumer工业相机Baumer工业相机BGAPI SDK的技术背景Baumer工业相机使用BGAPISDK控制相机数据流的方式1.引用合适的类文件2.使用BGAPISDK控制相机数据流的方式2.使用BGAPISDK控制…

el-select ios 上无法拉起 键盘

el-select 再添加 filterable属性支持输入搜索时&#xff0c;在ios上无法拉起键盘 解决 <el-selectref"selectRef"v-model"item.appId"clearable:filter-method"searchAppName"filterableplaceholder"请输入产品"hoot"setFo…

android什么意思是什么平板,什么是Android平板电脑? Android平板电脑列表【图形】...

平板电脑(Tablet Personal Computer)&#xff0c;也称为计算机&#xff0c;是一种轻巧紧凑的设备安卓平板电脑清理什么软件哪个好&#xff0c;使用户携带起来更方便. 现在这在我们的生活中已经很普遍&#xff0c;许会在日常工作中服用平板电脑. 数位板的另一个功能是它通过触摸…

vxe表格实现键盘上下左右方向键移动聚焦

vxe表格分为vxe-table一般表格和vxe-grid高级表格&#xff0c;两者之间的区别我就不说啦&#xff0c;我们来实现这两种表格用键盘按动上下左右方向键达到移动聚焦的效果。话不多说&#xff0c;上正文&#xff01;&#xff01;&#xff01; 首先在标签放入这两个事件&#xff1a…

计算机方向键是哪个键,你可能从来没碰过的键,电脑键盘方向键上面的3个按键有什么用?...

Hello大家好&#xff0c;我是兼容机之家的小牛。 我们在使用标准108键键盘的时候&#xff0c;经常只使用左边的英文字符区域和右边的小键盘区域&#xff0c;而方向键上方的3个按键大家可能从来没碰过&#xff0c;这些按键你知道它有哪些用处吗&#xff1f; 1、prt sc/sys rq键 …

被诺基亚冷落 英特尔MeeGo主攻平板电脑

在日前举行的2011年英特尔信息技术峰会&#xff08;简称IDF&#xff09;上&#xff0c;英特尔公司高级副总裁、软件与服务事业部总经理詹睿妮透露年内会有多款基于MeeGo操作系统的平板电脑上市。 今年2月&#xff0c;在诺基亚与英特尔合作的MeeGo操作系统即将迎来自己一岁生日时…

计算机上的win键是什么意思,win是电脑上哪个键

我们很多操作都会使用快捷键来完成&#xff0c;比如运行可以使用winr来快速打开&#xff0c;通过win键可以跟其他键组合来实现更多操作&#xff0c;可是因为键盘上没有win键字样&#xff0c;所以导致有一部分用户还不知道win是电脑上哪个键&#xff0c;其实这个win键就是键盘上…

电脑键盘上计算机是哪个键,普通计算机键盘上的哪个键是选项键?

Oo&#xff0c;城市管理团队的负责人 已安装硬件数字产品的手机数字 普通计算机键盘没有此键&#xff0c;某些特定型号不知道. 1. 该选项键是专门为Apple笔记本或台式计算机的键盘设计的. 2. 通常&#xff0c;其他品牌的键盘没有选项键&#xff0c;也没有此功能. 3. 它是Apple计…