【发布时间】:2018-04-30 15:37:36
【问题描述】:
根据我的阅读,线程访问同步方法的顺序是未指定的,因此是特定于实现的,但似乎在 Oracle Java 8(1.8.0_101-b13,Ubuntu 上的 64 位)中通常优先考虑最近调用的线程。
例如,当我运行以下类时:
class C
{
synchronized void go()
{
try
{
Thread.sleep(100);
System.out.println(Thread.currentThread().getName());
System.out.flush();
}
catch (Exception e)
{
System.out.println(e);
}
}
public static void main(String[] args)
{
C c = new C();
for (int i = 0; i < 100; i++)
{
Thread t = new Thread(((Runnable) c::go));
t.setName(Integer.toString(i));
t.start();
}
}
}
我通常会得到如下结果:
0 98 99 97 96 95 94 91 93 ... 4 3 2 1
任何人都可以确认 Oracle JVM 倾向于这样做吗?如果有什么特别的原因?
【问题讨论】:
-
线程是通过在大多数系统上使用进程来实现的。所以这将取决于你的操作系统的底层实现。您可能想询问 Ubuntu 开发人员,他们的信号量/阻塞系统是否在这方面表现出任何偏好。可能是阻塞进程的某种列表/队列。
-
你是什么意思,“最近调用线程?”示例中的每个线程都调用
go()并恰好锁定互斥锁一次。你的意思是,最近开始线程? -
您的示例没有很好地描述
synchronized的使用,因为它在持有锁的同时执行I/O。您应该避免将锁锁定的时间超过程序分配一些变量所需的时间。如果您遵循该规则,那么锁将很少发生争用,您将不在乎它是否“公平”。 -
@markspace,你是什么意思,“通过使用进程......?”在我所知道的几个操作系统中,线程是可执行上下文(线程是调度程序调度的内容),进程是资源(打开的文件、虚拟地址空间等)的集合,每个线程“属于“一个过程。在Linux操作系统中,从一开始就没有线程,“线程”的思想只是逐渐从“进程”的思想中解脱出来;但也有其他操作系统从一开始就将线程作为不同的实体。
-
@jameslarge 我从未听说过称为资源集合的过程。进程是一个可执行的上下文,就像一个线程。它恰好包含打开的文件等只是操作系统内务管理的必要实现。线程和进程的区别在于线程共享堆内存空间,而进程不共享。
标签: java multithreading synchronization