我试图理解
java中的内在锁.我有一个程序,我启动2个线程,它将循环通过并在同一个对象上调用synchronized方法.我希望两个线程并行执行,但看起来它是按顺序执行的.
如果我在循环中引入一个睡眠,那么它们会以随机顺序执行[正如我所料]
public class Synchronized {
private int valueM;
public Synchronized( int value) {
valueM = value;
}
synchronized
public void one() throws InterruptedException
{
System.out.println("Object[" + valueM + "] executing one");
Thread.sleep(100); //For case 2: comment it out
System.out.println("Object[" + valueM + "] completed one");
}
synchronized
public void two() throws InterruptedException
{
System.out.println("Object[" + valueM + "] executing two");
Thread.sleep(100); //For case 2: comment it out
System.out.println("Object[" + valueM + "] completed two");
}
}
测试代码:
@org.junit.jupiter.api.Test
void test_sync() throws InterruptedException
{
Synchronized obj = new Synchronized(1);
Runnable task_one = new Runnable() {
public void run() {
for (int i=0 ; i<10; i++)
{
try {
obj.one();
//Thread.sleep(100); //For case 2: uncomment it out
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
Runnable task_two = new Runnable() {
public void run() {
for (int i=0 ; i<10; i++)
{
try {
obj.two();
//Thread.sleep(100); //For case 2: uncomment it out
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
Thread t1 = new Thread(task_one);
Thread t2 = new Thread(task_two);
t1.start();
t2.start();
t1.join();
t2.join();
}
输出:
Case 1: output:
Object[1] executing one
Object[1] completed one
...10times
Object[1] executing two
Object[1] completed two
...10times
Case 2: output: random order
Object[1] executing one
Object[1] completed one
Object[1] executing two
Object[1] completed two
...
更新:
最初的问题是固定的..看起来它也是随机的,即使在案例1也是如此,但我只在加载更多迭代(30K)时才看到它.
因此,在没有睡眠的for循环中,线程切换发生的次数要少得多吗? Java-JVM是否特别尝试使用for循环将其作为“种类”原子(不完全但尽可能多?)执行?
最佳答案 内部锁定(synchronized关键字)被认为是“不公平”,这意味着无法保证锁定的获取率在竞争线程中是相同的.
众所周知,释放锁的线程通常更有可能再次获取它,从而导致您遇到的问题.
如果您希望您的线程具有类似的获取可能性(公平性),您可以使用像ReentrantLock这样的显式锁定,确保使用可选的布尔参数将其设置为true
ReentrantLock(boolean fair)
然后你就可以这样使用它
class X {
private final ReentrantLock lock = new ReentrantLock(true);
public void m() {
lock.lock();
try {
// method body
} finally {
lock.unlock()
}
}
}