仅当访问同一对象的相同方法时才锁定线程



我有一个对象,其中包含我的多线程项目的常用方法。某些方法是同步的。我的问题是当一个线程访问同步方法而另一个线程访问另一个同步方法时。这将使其中一个线程等待另一个线程。我想仅在访问相同的同步方法时才锁定线程,但我不知道如何。我发现最近关键字已同步。

这是我的方法之一。

public synchronized static void writeError(Exception err){
String time = longDate();//here will get personalized current date
//longDate is not synchronized.
try {
FileWriter  path = new FileWriter("ERROR - " + time + ".txt",true);
err.printStackTrace(new PrintWriter(path));
path.flush();
} catch (IOException e) {}
}

对这种方法有任何想法吗?

所以synchronized总是需要一个对象来操作。共享同一对象的所有synchronized块都是互斥的(即一次只有一个线程可以进入该块(。将synchronized放在方法声明中是简写的,例如方法等于synchronized(this),静态方法等于它synchronized(Foo.class)(其中Foo是包含静态方法的类(。

知道了这一点,您可以轻松创建多个要同步的对象,控制哪些方法可以同时运行,哪些方法不能。

允许方法3与方法1或方法2同时运行,但方法1和方法2互斥的示例类。此外,一次只能有一个线程运行每个方法。

public class Foo {
private final static Object lock1 = new Object();
private final static Object lock2 = new Object();
public static void method1() {
synchronized(lock1) {
...
}
}
public static void method2() {
synchronized(lock1) {
...
}
}
public static void method3() {
synchronized(lock2) {
...
}
}
}

还要注意静态与非静态。这里的方法是静态的,锁是静态的,所以一切都很好。如果方法是非静态的,它也会阻止在不同对象上调用方法,这可能不是您想要的。在这种情况下,使锁非静态将使每个Foo实例如前所述工作,但在foo1.method1()foo2.method2()的情况下不会有锁定,因为它们不会在同一对象上同步。

正如Shubham Kadlag的回答所表明的那样,synchronized远非Java唯一的并发工具。java.util.concurrent.locks包具有用于锁定的类(而synchronized是一种内置机制(。例如,ReentrantReadWriteLock允许您处理多个线程可以同时执行某些操作(读取(的情况,但一次只允许一个线程执行修改操作(写入(。它们还允许您为锁定提供超时,而synchronized会很乐意永远等待(不是经常需要tryLock(),因为如果您遇到死锁,这是一个编程错误(。

然后您意识到手动锁定无论如何都是针对笨蛋的,并发现java.util.concurrent有许多类可以向您隐藏锁定并提供各种高级功能。

正如Kamayan所提到的,对象的同步将满足您的需求。

此外,如果您有性能问题或有大量线程,则可以使用锁定。

请参阅 https://dzone.com/articles/synchronized-vs-lock

正如上面文章中指出的,同步最适合访问锁的少量线程(<4(,而 Lock 可能最适合访问相同锁的大量线程。

您可以参考 http://winterbe.com/posts/2015/04/30/java8-concurrency-tutorial-synchronized-locks-examples/以获取不同的锁定示例。

为所有方法创建一个单独的锁,如下所示。

private static ReentrantLock writeErrorlock = new ReentrantLock();
public static void writeError(Exception err){
writeErrorlock.lock();
String time = longDate();//here will get personalized current date
//longDate is not synchronized.
try {
FileWriter  path = new FileWriter("ERROR - " + time + ".txt",true);
err.printStackTrace(new PrintWriter(path));
path.flush();
} catch (IOException e) {
}
finally {
writeErrorlock.unlock();
}
}

最新更新