我有一个带有多线程项目常用方法的Object。有些方法是同步的。我的问题是当其中一个线程访问同步方法而另一个线程访问另一个同步方法时。这将使其中一个线程等待另一个。我只想在访问相同的同步方法时锁定线程,但我不知道如何。我最近发现了关键字synchronized。
这是我的一种方法。
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) {}
}
对这种方法有什么想法吗?
答案 0 :(得分:4)
所以synchronized
总是需要一个对象来操作。共享同一对象的所有synchronized
块都是互斥(即,一次只有一个线程可以进入块)。将synchronized
放在方法声明中是简单的,例如方法等于synchronized(this)
,静态方法是synchronized(Foo.class)
(其中Foo
是包含静态方法的类)。
了解这一点,您可以轻松创建多个同步对象,控制哪些方法可以同时运行,哪些方法不能同时运行。
允许method3与method1或method2同时运行的示例类,但method1和method2是互斥的。另外,每次只能运行一个线程。
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()
,因为如果你遇到死锁就会出现编程错误。)
然后你意识到无论如何手动锁定都是针对chumps的,并且发现java.util.concurrent
有许多类可以隐藏你的锁定并提供各种高级功能。
答案 1 :(得分:1)
正如Kamayan所说,对象的同步将满足您的需求。
此外,如果您遇到性能问题或者您拥有大量线程,则可以使用锁。
参考https://dzone.com/articles/synchronized-vs-lock
正如上面的帖子所指出的,synchronized最适合访问锁(< 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();
}
}