20240619-James-快速鸟瞰并发编程, 呕心沥血整理的架构技术(第2篇)

private String state;

synchronized String getState() {
if (state == null)
state = “Initial”;
return state;
}
}

第6节 不可变的对象

不可变对象具备执行安全的特性。此外,相较于可变对象,不可变对象通常也较合理,易于了解,而且提供较高的安全性。不可变对象的一个重要特性是它们都是线程安全的,因此不需要同步。当然对象不可变的是有如下要求滴:

  • 所有变量都是 final.
  • 所有变量必须是可变对象或不可变对象。
  • this 在构造方法执行期间引用不会逃脱。
  • 该类是final,因此无法在子类中覆盖此行为。

不可变对象的示例:

// 声明为final类
public final class JamesArtist {
// 不可变对象, 字段为final
private final String name;
//用于保存不可变对象, final类型
private final List tracks;

public JamesArtist(String name, List tracks) {
this.name = name;
//防止拷贝
List copy = new ArrayList<>(tracks);
//标记为不可更改
this.tracks = Collections.unmodifiableList(copy);
// “this”在构造期间不会传递到任何地方。
}

}

// 同上声明为final类
public final class JamesTrack {
// 不可变对象, 字段为final
private final String title;

public JamesTrack(String title) {
this.title = title;
}
}

第7节 线程Thread类

java.lang.Thread类用于表示应用程序或JVM线程。代码总是在某些Thread类的上下文中执行(用于Thread#currentThread()获取自己的Thread)。

线程状态如下

状态描述
NEW没有开始。
RUNNABLE启动并运行。
BLOCKED在监视器上等待 - 尝试获取锁并进入关键部分。
WAITING等待另一个线程执行特定操作(notify/notifyAllLockSupport#unpark)。
TIMED_WAITING相同WAITING,但是为等待超时。
TERMINATED停止。

线程协调方法如下

线程方法描述
start(启动)启动Thread实例并执行其run()方法。
join(阻止)阻止直到Thread完成。
interrupt(中断)中断线程。如果线程在响应中断的方法中被阻塞,InterruptedException则将在另一个线程中抛出一个线程,否则将设置中断状态。
stop(停止), suspend(暂停), resume(恢复), destroy(销毁)这些方法都已弃用。根据相关线程的状态执行的操作不安全。

怎么处理InterruptedException异常?

  • 在重新抛出 InterruptedException 之前执行特定于任务的清理工作。
  • 声明当前方法抛出 InterruptedException.
  • 如果未声明某个方法抛出InterruptedException,则应通过调用将中断的标志恢复为true,Thread.currentThread().interrupt()并且应该抛出一个更合适的异常。将标志设置为true非常重要,以便有机会处理更高级别的中断。

不可预知的异常处理

线程可以指定UncaughtExceptionHandler将接收任何导致线程突然终止的未捕获异常的通知。

Thread thread = new Thread(runnable);
thread.setUncaughtExceptionHandler((failedThread,exception)->
{
logger.error(“Caught unexpected exception in thread
‘{}’.”, failedThread.getName(), exception);
});thread.start();

第8节 线程的活跃度

死锁

当存在多个线程时会发生死锁,每个线程等待另一个线程持有的资源,从而形成资源循环和获取线程。

潜在的死锁示例:

class JamesAccount {
private long amount;

void plus(long amount) {
this.amount += amount;
}

void minus(long amount) {
if (this.amount < amount)
throw new IllegalArgumentException();
else
this.amount -= amount;
}

static void transferWithDeadlock(long amount, JamesAccount first, JamesAccount second) {
synchronized (first) {
synchronized (second) {
first.minus(amount);
second.plus(amount);
}
}
}
}

如果同时发生死锁:

  • 一个线程正在尝试从第一个帐户转移到第二个帐户,并且已经获得了第一个帐户的锁。
  • 另一个线程正在尝试从第二个帐户转移到第一个帐户,并且已经获得了第二个帐户的锁。

避免死锁的技巧:

  • 锁定顺序 - 始终以相同的顺序获取锁。

class JamesAccount {
private long id;
private long amount;

// 此处省略了一些方法
static void transferWithLockOrdering(long amount, JamesAccount first, JamesAccount second) {
boolean lockOnFirstAccountFirst = first.id < second.id;
Account firstLock = lockOnFirstAccountFirst ? first : second;
Account secondLock = lockOnFirstAccountFirst ? second : first;
synchronized (firstLock) {
synchronized (secondLock) {
first.minus(amount);
second.plus(amount);
}
}
}
}

  • 锁定超时 - 在获取锁时不要无限制地阻塞,应该释放所有锁后再尝试。

class JamesAccount {
private long amount;

//省略了一些方法
static void transferWithTimeout(long amount, JamesAccount first, JamesAccount second, int retries, long timeoutMillis)
throws InterruptedException {
for (int attempt = 0; attempt < retries; attempt++) {
if (first.lock.tryLock(timeoutMillis, TimeUnit.MILLISECONDS)) {
try {
if (second.lock.tryLock(timeoutMillis, TimeUnit.MILLISECONDS)) {
try {
first.minus(amount);
second.plus(amount);
} finally {
second.lock.unlock();
}
}
} finally {
first.lock.unlock();
}
}
}
}
}

面试宝典

面试必问知识点、BATJ历年历年面试真题+解析

学习经验总结

(一)调整好心态
心态是一个人能否成功的关键,如果不调整好自己的心态,是很难静下心来学习的,尤其是现在这么浮躁的社会,大部分的程序员的现状就是三点一线,感觉很累,一些大龄的程序员更多的会感到焦虑,而且随着年龄的增长,这种焦虑感会越来越强烈,那么唯一的解决办法就是调整好自己的心态,要做到自信、年轻、勤奋。这样的调整,一方面对自己学习有帮助,另一方面让自己应对面试更从容,更顺利。

(二)时间挤一挤,制定好计划
一旦下定决心要提升自己,那么再忙的情况下也要每天挤一挤时间,切记不可“两天打渔三天晒网”。另外,制定好学习计划也是很有必要的,有逻辑有条理的复习,先查漏补缺,然后再系统复习,这样才能够做到事半功倍,效果才会立竿见影。

(三)不断学习技术知识,更新自己的知识储备
对于一名程序员来说,技术知识方面是非常重要的,可以说是重中之重。**要面试大厂,自己的知识储备一定要非常丰富,若缺胳膊少腿,别说在实际工作当中,光是面试这一关就过不了。**对于技术方面,首先基础知识一定要扎实,包括自己方向的语言基础、计算机基础、算法以及编程等等。

有条理的复习,先查漏补缺,然后再系统复习,这样才能够做到事半功倍,效果才会立竿见影。

(三)不断学习技术知识,更新自己的知识储备
对于一名程序员来说,技术知识方面是非常重要的,可以说是重中之重。**要面试大厂,自己的知识储备一定要非常丰富,若缺胳膊少腿,别说在实际工作当中,光是面试这一关就过不了。**对于技术方面,首先基础知识一定要扎实,包括自己方向的语言基础、计算机基础、算法以及编程等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值