gpt4 book ai didi

java - 对于 MyStructure 的每个初始化类型,具有 AspectJ 切入点的 ReentrantReadWriteLock

转载 作者:行者123 更新时间:2023-12-02 10:36:19 26 4
gpt4 key购买 nike

我正在努力使用 AspectJ 为每个构造的、属于 Mystruct 类型的对象创建一个 ReentrantReadWriteLock。这是我的源代码。

方面类

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

@Aspect
public class LocksAspect {
private ReentrantReadWriteLock rwLock;
private Lock acquireReadLock;
private Lock acquireWriteLock;

@Before("!within(LocksAspect)&&execution(*.new(..))")
public void LookupBefores() {
rwLock = new ReentrantReadWriteLock();
acquireReadLock = rwLock.readLock();
acquireWriteLock = rwLock.writeLock();
}

@Pointcut("call(void MyStructure.Insert(String))")
public void InsertPointcut() {
}

@Pointcut("call(void MyStructure.Read(int))")
public void ReadPointcut() {
}

@Before("InsertPointcut()")
public void InsertPointcutBefore(JoinPoint pointcut) throws InterruptedException {
acquireWriteLock.lock();
String thrdName = Thread.currentThread().getName();
System.out.println(thrdName + " is entering in critical Section {} ");
Thread.sleep(10000);
}


@After("InsertPointcut()")
public void InsertPointcutAfter(JoinPoint pointcut) {
String thrdName = Thread.currentThread().getName();
System.out.println(thrdName + " received notification and is exiting critical Section {} ");
acquireWriteLock.unlock();
}

@Before("ReadPointcut()")
public void ReadPointcutBefore(JoinPoint pointcut) throws InterruptedException {
acquireReadLock.lock();
String thrdName = Thread.currentThread().getName();
System.out.println(thrdName + " is entering in critical Section {} ");
Thread.sleep(1000);
}


@After("ReadPointcut()")
public void ReadPointcutAfter(JoinPoint pointcut) {
String thrdName = Thread.currentThread().getName();
System.out.println(thrdName + " received notification and is exiting critical Section {} ");
acquireReadLock.unlock();
}
}

Thread writer 类。(Reader 线程类并不重要,因为我的问题不同,所以我省略了它)

public class Writer extends Thread{
private MyStructure myStructure;
public Writer(MyStructure myStructure) {
this.myStructure=myStructure;
}

@Override
public void run() {
this.myStructure.Insert("example");
}
}

我的结构类

import java.util.ArrayList;

public class MyStructure {
ArrayList<String> examplelist;

public MyStructure() {
examplelist = new ArrayList<String>();
}

public void Insert(String value) {
examplelist.add(value);
}

public void Read(int pos) {
examplelist.get(pos);
}
}

主要内容

MyStructure structure = new MyStructure();
MyStructure structure1 = new MyStructure();
new Thread(new Writer(structure), "Thread1").start();
new Thread(new Writer(structure1), "Thread2").start();

输出

Thread2  is entering in critical Section {} 
Thread2 received notification and is exiting critical Section {}
Thread1 is entering in critical Section {} //Thread1 will wait for Thread2 to release the lock in critical section which is wrong
Thread1 received notification and is exiting critical Section {}

现在我的问题是如何为创建的 Mystruct 的每个对象获取新的 ReentrantReadWriteLock 。例如,如果我们运行上面的示例,Thread1 和 Thread2 都必须能够访问临界区,因为它们具有不同的对象引用,但这不应该发生。我的问题是 Thread2 将阻塞并等待 Thread1 完成,这是错误的。如何绕过 Aspect4j 的构建问题?

最佳答案

解决问题的关键是每个MyStructure需要一组锁。实例。不过,您的方面是单例。因此,您要么需要使用另一个方面实例化方案(这就是我将在我的答案中使用的方案),要么通过保留一组锁来在单例方面进行手动簿记,并在 MyStructure 时向该集中添加一个新元素。对象已创建。

为了更好地理解我的回答,请引用AspectJ手册了解aspect instantiation的信息.

在我们开始之前,先说一些关于您的代码的评论以及为什么我对其进行了一些更改:

  • 您的Writer已经是 Thread子类,无需将其包装到另一个线程实例中。 (我知道您这样做可能只是为了能够命名线程,但这可以通过在类中添加一个构造函数来实现,该构造函数接受名称参数并将其传递给父类(super class)构造函数。)
  • 您不应调用 JoinPoint 类型的变量pointcut因为连接点不是 AOP 方面的切入点。
  • 我将日志记录分解到它自己的辅助方法中,并对其进行了一些改进,以便我们可以更清楚地看到何时发生的情况。
  • 我决定用周围建议替换每对前后建议。当然,这是可选的,但在这种情况下我更喜欢在一个地方看到控制流。顺便说一句,请小心将周围建议的返回类型更改为 Object如果您想针对非 void 方法,则实际上会返回一些内容。在这里这是没有必要的,因为在这两种情况下我们都有 void 方法。
  • 我还决定内联切入点,这也是可选的,但为了演示目的使示例代码更加简洁。
  • 我添加了 Reader类并使用它来显示可重入读锁与写锁之间的区别。
  • 我还负责制作MyStructure可命名和可打印的实例,以便在日志中更轻松地识别目标对象。
  • 我随机化了读取器/写入器线程的执行顺序,以便以更真实的方式混合它们。为了避免从新创建的MyStructure读取时出现异常污染日志。在写入之前,我确保 MyStructure在构造函数中获取默认元素。为了保持示例代码简单,我不想在这里捕获异常。
  • 我将方面放在应用程序代码之外的另一个包中,以便演示在使用注释样式 AspectJ 时通常需要使用完全限定的类名(在 native 语法中导入就足够了)。

现在有什么解决办法吗?基本上就是这样,因为上面提到的更改只是使代码更好或测试程序更接近现实生活情况:

@Aspect("pertarget(execution(de.scrum_master.app.MyStructure.new(..)))")
public class LocksAspect { // (...)

这会为每个MyStructure创建一个方面实例。目的。这也是为什么我们可以分配 readWriteLock 的值。 , readLockwriteLock直接而不是像在单例方面那样使用特殊的切入点+建议对。

这是完整的、重构的示例代码:

应用程序代码+驱动程序应用程序:

package de.scrum_master.app;

import java.util.ArrayList;
import java.util.List;

public class MyStructure {
private String name;
private List<String> myList;

public MyStructure(String name) {
this.name = name;
myList = new ArrayList<String>();
myList.add("dummy element to permit reading");
}

public void insert(String value) {
myList.add(value);
}

public void read(int pos) {
myList.get(pos);
}

@Override
public String toString() {
return "MyStructure[" + name + "]";
}
}
package de.scrum_master.app;

public class Writer extends Thread {
private MyStructure myStructure;

public Writer(MyStructure myStructure) {
this.myStructure = myStructure;
}

@Override
public void run() {
myStructure.insert("example");
}
}
package de.scrum_master.app;

public class Reader extends Thread {
private MyStructure myStructure;

public Reader(MyStructure myStructure) {
this.myStructure = myStructure;
}

@Override
public void run() {
myStructure.read(0);
}
}
package de.scrum_master.app;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Application {
public static void main(String[] args) {
MyStructure structureA = new MyStructure("One");
MyStructure structureB = new MyStructure("Two");
List<Thread> threads = Arrays.asList(
new Writer(structureA), new Writer(structureB), new Writer(structureA), new Writer(structureB),
new Reader(structureA), new Reader(structureB), new Reader(structureA), new Reader(structureB),
new Reader(structureA), new Reader(structureB), new Reader(structureA), new Reader(structureB)
);
Collections.shuffle(threads);
for (Thread thread : threads)
thread.start();
}
}

方面:

package de.scrum_master.aspect;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import de.scrum_master.app.MyStructure;

@Aspect("pertarget(execution(de.scrum_master.app.MyStructure.new(..)))")
public class LocksAspect {
private static final long startTime = System.currentTimeMillis();

private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Lock readLock = readWriteLock.readLock();
private Lock writeLock = readWriteLock.writeLock();

@Around("target(myStructure) && execution(void insert(String))")
public void InsertPointcutBefore(ProceedingJoinPoint thisJoinPoint, MyStructure myStructure) throws Throwable {
writeLock.lock();
log("entering write section", myStructure);
try {
Thread.sleep(1000);
thisJoinPoint.proceed();
} finally {
log("exiting write section", myStructure);
writeLock.unlock();
}
}

@Around("target(myStructure) && execution(void read(int))")
public void ReadPointcutBefore(ProceedingJoinPoint thisJoinPoint, MyStructure myStructure) throws Throwable {
readLock.lock();
log("entering read section", myStructure);
try {
Thread.sleep(1000);
thisJoinPoint.proceed();
} finally {
log("exiting read section", myStructure);
readLock.unlock();
}
}

private static void log(String message, Object targetObject) {
System.out.printf(
"%8d ms | %-25s | %-17s | %s%n",
System.currentTimeMillis() - startTime,
Thread.currentThread(),
targetObject,
message
);
}
}

日志输出示例:

       4 ms | Thread[Thread-3,5,main]   | MyStructure[Two]  | entering write section
4 ms | Thread[Thread-6,5,main] | MyStructure[One] | entering read section
4 ms | Thread[Thread-8,5,main] | MyStructure[One] | entering read section
4 ms | Thread[Thread-4,5,main] | MyStructure[One] | entering read section
4 ms | Thread[Thread-10,5,main] | MyStructure[One] | entering read section
1019 ms | Thread[Thread-3,5,main] | MyStructure[Two] | exiting write section
1020 ms | Thread[Thread-8,5,main] | MyStructure[One] | exiting read section
1020 ms | Thread[Thread-4,5,main] | MyStructure[One] | exiting read section
1020 ms | Thread[Thread-11,5,main] | MyStructure[Two] | entering read section
1020 ms | Thread[Thread-5,5,main] | MyStructure[Two] | entering read section
1020 ms | Thread[Thread-6,5,main] | MyStructure[One] | exiting read section
1020 ms | Thread[Thread-10,5,main] | MyStructure[One] | exiting read section
1025 ms | Thread[Thread-2,5,main] | MyStructure[One] | entering write section
2023 ms | Thread[Thread-11,5,main] | MyStructure[Two] | exiting read section
2024 ms | Thread[Thread-5,5,main] | MyStructure[Two] | exiting read section
2025 ms | Thread[Thread-1,5,main] | MyStructure[Two] | entering write section
2026 ms | Thread[Thread-2,5,main] | MyStructure[One] | exiting write section
2026 ms | Thread[Thread-0,5,main] | MyStructure[One] | entering write section
3026 ms | Thread[Thread-1,5,main] | MyStructure[Two] | exiting write section
3026 ms | Thread[Thread-7,5,main] | MyStructure[Two] | entering read section
3026 ms | Thread[Thread-9,5,main] | MyStructure[Two] | entering read section
3028 ms | Thread[Thread-0,5,main] | MyStructure[One] | exiting write section
4028 ms | Thread[Thread-7,5,main] | MyStructure[Two] | exiting read section
4029 ms | Thread[Thread-9,5,main] | MyStructure[Two] | exiting read section

关于java - 对于 MyStructure 的每个初始化类型,具有 AspectJ 切入点的 ReentrantReadWriteLock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53270967/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com