例1:
public class MyServlet extends HttpServlet {
// 是否安全
Map<String, Object> map = new HashMap<>();
// 是否安全
String S1 = "...";
// 是否安全
final String s2 = "...";
Date D1 = new Date();
// 是否安全
final Date D2 = new Date();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
// 使用上述变量
}
}
分析

答案
Map<String, Object> map = new ConcurrentHashMap<>();
final LocalDateTime s2 = LocalDateTime.now();
LocalDateTime D1 = LocalDateTime.now();
final LocalDateTime D2 = LocalDateTime.now();
例二
public class MyServlet extends HttpServlet {
// 是否安全?
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
// 记录调用次数
private int count = 0;
public void update() {
// ...
count++;
}
}
思路

答案
public class MyServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update();
}
}
public class UserServiceImpl implements UserService {
private AtomicInteger count = new AtomicInteger(0);
public void update() {
// ...
count.incrementAndGet();
}
}
例三
@Aspect
@Component
public class MyAspect 【
// 是否安全
private long start = 0L;
@Before("execution(* *(..))")
public void before() {
start = System.nanoTime();
}
@After("execution(* *(..))")
public void after() {
long end = System.nanoTime();
System.out.println("cost time:" + (end - start));
}
}
思路
思路一
@Aspect
@Componet
public class MyAspect {
private ThreadLocal<Long> startTime = new ThreadLocal<>();
@Before("execution(* *(..))")
public void before() {
startTime.set(System.nanoTime());
}
@After("execution(* *(..))")
public void after() {
long end = System.nanoTime();
long start = startTime.get();
System.out.println("cost time:" + (end - start));
startTime.remove(); // 清理 ThreadLocal, 防止内存泄漏
}
}
对象
- 线程安全,每个线程都有自己的
start值 - 简单易用,适用这种需要在线程间隔离状态的场景
缺点
- 需要手动清理
ThreadLocal(调用remove()), 否则可能会导致内存泄漏(尤其是在线程池场景中)
思路二
@Aspect
@Component
public class MyAspect {
@Around("execution(* *(..))")
public void around(ProceddingJoinPoint joinPoint) throws Thtowable {
long start = System.nanoTime();
joinPoint.proceed() // 执行目标方法
long end = System.nanoTime();
System.out.println("cost time:" + (end - start));
}
}
答案
@Aspect
@Component
public class MyAspect {
private ThreadLoca<Long> startTime = new ThreaddLocal<>();
@Before("execution(* *(..))")
public void before() {
startTime.set(System.nanoTime());
}
@After("execution( *(..))")
public void after() {
long end = System.nanoTime();
long start = System.get();
System.out.println("cost time:" + (end - start));
startTime.remove(); // 清理 ThreadLocal, 防止内存泄漏
}
}
例四
public class MyServlet extends HttpServlet {
// 是否安全
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
// 是否安全
private UserDao userDao = new UserDaoImpl();
public void update() {
userDao.update();
}
}
public class UserDaoImpl implements UserDao {
public void update() {
String sql = "update user set password = ? where username = ?"
// 是否安全
try (Connection conn = DriverManager.getConnection("","","")) {
// ...
} catch (Exception e) {
// ...
}
}
}
思路



答案
public class MyServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
public void update() {
userDao.update();
}
}
public class UserDaoImpl implements UserDao {
private DataSource dataSource; // 通过依赖注入获取连接池
public UserDaoImpl(DataSource dataSource) {
this.dataSource = dataSource;
}
public void update() {
String sql = "update user set password = ? where username = ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, password);
pstmt.setString(2, username);
pstmt.executeUpdate();
} catch (Exception e) {
// ...
}
}
}
例5
public class MyServlet extends HttpServlet {
// 是否安全
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) 【
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
// 是否安全
private UserDao userDao = new UserDaoImpl();
public void update() {
userDao.update();
}
}
public class UserDaoImp implements UserDao {
// 是否安全
private Connection conn = null;
public void update() throws SQLException {
String sql = "update user set password = ? where username = ?"
conn = DriverManager.getConnection("","","");
// ...
conn.close();
}
}
思路

答案
public class MyServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
public void update() {
userDao.update();
}
}
public class UserDaoImpl implements UserDao {
private DataSource dataSource; // 通过依赖注入获取连接池
public UserDaoImpl(DataSource dataSource) {
this.dataSource = dataSource;
}
public void update() throws SQLException {
String sql = "update user set password = ? where username = ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 设置参数
pstmt.setString(1, password);
pstmt.setString(2, username);
pstmt.executeUpdate();
}
}
}
例6
public class MyServlet extedns HttpServlet {
// 是否安全
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletReponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
pubilc void update() {
UserDao userDao = new UserDaoImpl();
userDao.update();
}
}
public class UserDaoImpl implements UserDao {
// 是否安全
private Connection = null;
public void update() throws SQLException {
String sql = "update user set password = ? where username ?"
conn = DriverManager.getConnection("", "", "")l
// ...
conn.close();
}
}
思路

答案
public class UserDaoImpl implements UserDao {
private DataSource dataSource; // 通过依赖注入获取连接池
public UserDaoImpl(DataSource dataSource) {
this.dataSource = dataSource;
}
public void update() throws SQLException {
String sql = "update user set password = ? where username = ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 设置参数
pstmt.setString(1, password);
pstmt.setString(2, username);
pstmt.executeUpdate();
}
}
}
例7
public abstract class Test {
public void bar() {
// 是否安全
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
foo(sdf);
}
public abstract foo(SimpleDateFormat sdf);
public static void main(String[] args) {
new Test().bar();
}
}
其中 foo 的行为是不确定的,可能导致不安全的发生,被称为外星方法
public void foo(SimpleDateFormat sdf) {
String dateStr = "1999-10-11 00:00:00";
for (int i = 0; i < 20; i++) {
new Thread(() -> {
try {
sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
}).start();
}
}
请比较 JDK 中 String 类的实现
思路

答案
public void foo() {
String dateStr = "1999-10-11 00:00:00";
for (int i = 0; i < 20; i++) {
new Thread(() -> {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.parse(dateStr); // 每个线程有自己的 sdf 实例
} catch (ParseException e) {
e.printStackTrace();
}
}).start();
}
}
例八
private static Integer i = 0;
public static void main(String[] args) throws InterruptedException 【
List<Thread> list = new ArrayLIst<>();
for (int j = 0; j < 2; j++) {
Thread thread = new Thread(() -> {
for (int k = 0; k < 5000; k++) [
synchronized (i) {
i++;
}
}
}, " " + j);
list.add(thread);
}
list.stream().forEach(t -> t.start());
list.stream().forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
思路

- 适用
AtomicInteger - 适用显式锁(
ReentrantLock) - 使用
synchronized锁固定对象
答案
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
private static AtomicInteger i = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
List<Thread> list = new ArrayList<>();
for (int j = 0; j < 2; j++) {
Thread thread = new Thread(() -> {
for (int k = 0; k < 5000; k++) {
i.incrementAndGet(); // 原子操作
}
}, " " + j);
list.add(thread);
}
list.forEach(Thread::start);
list.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("Final value of i: " + i.get());
}
}
卖票问题


public class ExerciseSell {
public static void main(String[] args) {
TicketWindow ticketWindow = new TicketWindow(2000);
List<Thread> list = new ArrayList<>();
// 用来存储买出去多少张票
List<Integer> sellCount = new Vector<>();
for (int i = 0; i < 2000; i++) {
Thread t = new Thread(() -> {
// 分析这里的竞态条件
int count = ticketWindow.sell(randomAmount());
sellCount.add(count);
});
list.add(t);
t.start();
}
list.forEach((t) -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 买出去的票求和
log.debug("selled count:{}", sellCount.stream().mapToInt(c -> c).sum());
// 剩余票数
log.debug("remainder count:{}", ticketWindow.getCount());
}
// Random 为线程安全
static Random random = new Random();
// 随机 1~5
public static int randomAmount() {
return random.nextInt(5) + 1;
}
}
class TicketWindow {
private int count;
public TicketWindow(int count) {
this.count = count;
}
public int getCount() {
return count;
}
public int sell(int amount) {
if (this.count >= amount) {
this.count -= amount;
return amount;
} else {
return 0;
}
}
}

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Vector;
public class ExerciseSell {
public static void main(String[] args) {
TicketWindow ticketWindow = new TicketWindow(2000);
List<Thread> list = new ArrayList<>();
List<Integer> sellCount = new Vector<>(); // 使用 Vector 确保线程安全
for (int i = 0; i < 2000; i++) {
Thread t = new Thread(() -> {
int count = ticketWindow.sell(randomAmount());
sellCount.add(count);
});
list.add(t);
t.start();
}
list.forEach((t) -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("selled count: " + sellCount.stream().mapToInt(c -> c).sum());
System.out.println("remainder count: " + ticketWindow.getCount());
}
static Random random = new Random();
public static int randomAmount() {
return random.nextInt(5) + 1;
}
}
class TicketWindow {
private int count;
public TicketWindow(int count) {
this.count = count;
}
public synchronized int getCount() {
return count;
}
public synchronized int sell(int amount) {
if (this.count >= amount) {
this.count -= amount;
return amount;
} else {
return 0;
}
}
}
转账练习
public class ExerciseTransfer {
public static void main(String[] args) throws InterruptedException {
Account a = new Account(1000);
Account b = new Account(1000);
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
a.transfer(b, randomAmount());
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
b.transfer(a, randomAmount());
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
// 查看转账2000次后的总金额
log.debug("total:{}", (a.getMoney() + b.getMoney()));
}
// Random 为线程安全
static Random random = new Random();
// 随机 1~100
public static int randomAmount() {
return random.nextInt(100) + 1;
}
}
class Account {
private int money;
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public void transfer(Account target, int amount) {
if (this.money > amount) {
this.setMoney(this.getMoney() - amount);
target.setMoney(target.getMoney() + amount);
}
}
}
这样改正行不行,为什么?
public synchronized void transfer(Account target, int amount) {
if (this.money > amount) {
this.setMoney(this.getMoney() - amount);
target.setMoney(target.getMoney() + amount);
}
}

改进后的代码使用全局锁
import java.util.Random;
public class ExerciseTransfer {
public static void main(String[] args) throws InterruptedException {
Account a = new Account(1000);
Account b = new Account(1000);
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
a.transfer(b, randomAmount());
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
b.transfer(a, randomAmount());
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("total: " + (a.getMoney() + b.getMoney()));
}
static Random random = new Random();
public static int randomAmount() {
return random.nextInt(100) + 1;
}
}
class Account {
private int money;
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public void transfer(Account target, int amount) {
synchronized (Account.class) {
if (this.money > amount) {
this.setMoney(this.getMoney() - amount);
target.setMoney(target.getMoney() + amount);
}
}
}
}

1917

被折叠的 条评论
为什么被折叠?



