java 不使用“同步”关键字的线程安全代码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10330941/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Thread-safe code without using the `synchronized` keyword?
提问by chhaya
What are the possible ways to make code thread-safe without using the synchronized
keyword?
在不使用synchronized
关键字的情况下使代码线程安全的可能方法是什么?
回答by Malcolm
Actually, lots of ways:
其实方法很多:
- No need for synchronization at all if you don't have mutable state.
- No need for synchronization if the mutable state is confined to a single thread. This can be done by using local variables or
java.lang.ThreadLocal
. - You can also use built-in synchronizers.
java.util.concurrent.locks.ReentrantLock
has the same functionality as the lock you access when usingsynchronized
blocks and methods, and it is even more powerful.
- 如果您没有可变状态,则根本不需要同步。
- 如果可变状态仅限于单个线程,则不需要同步。这可以通过使用局部变量或
java.lang.ThreadLocal
. - 您还可以使用内置同步器。
java.util.concurrent.locks.ReentrantLock
与使用synchronized
块和方法时访问的锁具有相同的功能,并且功能更加强大。
回答by NimChimpsky
Only have variables/references local to methods. Or ensure that any instance variables are immutable.
只有方法本地的变量/引用。或者确保任何实例变量都是不可变的。
回答by Kalpak Gadre
You can make your code thread-safe by making all the data immutable, if there is no mutability, everything is thread-safe.
您可以通过使所有数据不可变来使代码线程安全,如果没有可变性,则一切都是线程安全的。
Secondly, you may want to have a look at java concurrent API which has provision for providing read / write locks which perform better in case there are lots of readers and a few writers. Pure synchronized keyword will block two readers also.
其次,您可能想看看 java 并发 API,它提供了提供读/写锁的条款,如果有很多读者和少数作者,这些锁会表现得更好。纯synchronized关键字也会阻塞两个读者。
回答by Ayaz Ahmad
////////////FIRST METHOD USING SINGLE boolean//////////////
public class ThreadTest implements Runnable {
ThreadTest() {
Log.i("Ayaz", "Constructor..");
}
private boolean lockBoolean = false;
public void run() {
Log.i("Ayaz", "Thread started.." + Thread.currentThread().getName());
while (lockBoolean) {
// infinite loop for other thread if one is accessing
}
lockBoolean = true;
synchronizedMethod();
}
/**
* This method is synchronized without using synchronized keyword
*/
public void synchronizedMethod() {
Log.e("Ayaz", "processing...." + Thread.currentThread().getName());
try {
Thread.currentThread().sleep(3000);
} catch (Exception e) {
System.out.println("Exp");
}
Log.e("Ayaz", "complete.." + Thread.currentThread().getName());
lockBoolean = false;
}
} //end of ThreadTest class
//For testing use below line in main method or in Activity
ThreadTest threadTest = new ThreadTest();
Thread threadA = new Thread(threadTest, "A thead");
Thread threadB = new Thread(threadTest, "B thead");
threadA.start();
threadB.start();
///////////SECOND METHOD USING TWO boolean/////////////////
public class ThreadTest implements Runnable {
ThreadTest() {
Log.i("Ayaz", "Constructor..");
}
private boolean isAnyThreadInUse = false;
private boolean lockBoolean = false;
public void run() {
Log.i("Ayaz", "Thread started.." + Thread.currentThread().getName());
while (!lockBoolean)
if (!isAnyThreadInUse) {
isAnyThreadInUse = true;
synchronizedMethod();
lockBoolean = true;
}
}
/**
* This method is synchronized without using synchronized keyword
*/
public void synchronizedMethod() {
Log.e("Ayaz", "processing...." + Thread.currentThread().getName());
try {
Thread.currentThread().sleep(3000);
} catch (Exception e) {
System.out.println("Exp");
}
Log.e("Ayaz", "complete.." + Thread.currentThread().getName());
isAnyThreadInUse = false;
}
} // end of ThreadTest class
//For testing use below line in main method or in Activity
ThreadTest threadTest = new ThreadTest();
Thread t1 = new Thread(threadTest, "a thead");
Thread t2 = new Thread(threadTest, "b thead");
t1.start();
t2.start();
回答by OldCurmudgeon
To maintain predictability you must either ensure all access to mutable data is made sequentially or handle the issues caused by parallel access.
为了保持可预测性,您必须确保对可变数据的所有访问都是按顺序进行的,或者处理由并行访问引起的问题。
The most gross protection uses the synchronized
keyword. Beyond that there are at least two layers of possibility, each with their benefits.
最粗略的保护使用synchronized
关键字。除此之外,至少有两层可能性,每一层都有其好处。
Locks/Semaphores
锁/信号量
These can be very effective. For example, if you have a structure that is read by many threads but only updated by one you may find a ReadWriteLock
useful.
这些可能非常有效。例如,如果您有一个由多个线程读取但仅由一个线程更新的结构,您可能会发现它ReadWriteLock
很有用。
Locks can be much more efficient if you choose your lock to match the algorithm.
如果您选择与算法匹配的锁,锁会更有效率。
Atomics
原子
Use of AtomicReference
for example can often provide completely lock free functionality. This can usually provide huge benefits.
AtomicReference
例如的使用通常可以提供完全无锁的功能。这通常可以提供巨大的好处。
The reasoning behind atomics is to allow them to fail but to tell you they failed in a way you can handle it.
原子背后的推理是允许它们失败,但告诉您它们以您可以处理的方式失败。
For example, if you want to change a value you can read it and then write its new value so long as it is still the old value. This is called a "compare and set" or cas
and can usually be implemented in hardware and so is extremely efficient. All you then need is something like:
例如,如果你想改变一个值,你可以读取它,然后写入它的新值,只要它仍然是旧值。这称为“比较并设置” cas
,通常可以在硬件中实现,因此非常有效。然后你需要的只是:
long old = atomic.get();
while ( !atomic.cas(old, old+1) ) {
// The value changed between my get and the cas. Get it again.
old = atomic.get();
}
Note, however, that predictability is not always the requirement.
但是请注意,可预测性并不总是必要的。
回答by Bilal Abdulkany
Well there are many ways you can achieve this, but each contains many flavors. Java 8 also ships with new concurrency features.
Some ways you could make sure thread safety are: Semaphores
Locks-Reentrantlock,ReadWriteLock,StampedLock
(Java 8)
有很多方法可以实现这一点,但每种方法都包含多种口味。Java 8 还附带了新的并发特性。您可以确保线程安全的一些方法是:Semaphores
锁- Reentrantlock,ReadWriteLock,StampedLock
(Java 8)
回答by Kshitij
Why do u need to do it?
为什么你需要这样做?
Using only local variable/references will not solve most of the complex business needs. Also, if instance variable are immutable, their references can still be changed by other threads.
仅使用局部变量/引用并不能解决大多数复杂的业务需求。此外,如果实例变量是不可变的,它们的引用仍然可以被其他线程更改。
One option is use something like a SingleThreadModel, but it is highly discouraged and deprecated.
一种选择是使用类似SingleThreadModel 的东西,但它是非常不鼓励和弃用的。
u can also look at concurrent api as suggested above by Kal
您还可以查看Kal上面建议的并发 api