На данный момент существует множество многоядерных пользовательских систем.
Но все мы знаем что Java напрямую не может обращаться к системным ресурсам, потому как ограничена средой JVM.
Многозадачность в Java так же ограничена средой JVM, но тем не менее существует возможность привязать конкретный Java thread на любое процессорное ядро (или на 2 или на 3 в произвольном сочетании).
Все что нам нужно из сторонних библиотек это JNA (Java Native Access).
На главной странице проекта (https://jna.dev.java.net) читаем –
JNA позволяет программам на Java получать удобный и простой доступ к внешним системным библиотекам (Windows dll), при этом писать нативный (с++) код, а так же пользоваться JNI нет необходимости. Доступ к dll осуществляется динамически, не требуется предварительно генерировать промежуточный код.
Разработчику нужно описать интерфейс (Java) описывающий нужные функции целевой библиотеки (dll).
1. Создаем класс KernelThreadSupport (естественно назвать можно как угодно)
package org.guap;
// импортируем нужные классы из библиотеки jna
// их можно скачать с сайта https://jna.dev.java.net
import com.sun.jna.Native;
import com.sun.jna.Library;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
public class KernelThreadSupport {
// создаем статическую переменную нашего интерфейса
// при этом мы получим интерфейсный класс позволяющий вызвать
// метод SetThreadAffinityMask из dll kernel32
public static ThreadSupport threadSupport =
(ThreadSupport) Native.loadLibrary("kernel32", ThreadSupport.class);
// Kernel32 это класс взятый из архива, я просто присоеденил к проекту examples.zip,
// архив этот скачал с того же сайта
// внутри class файлы уже описанных методов библиотеки kernel32
//(но не всех, как раз SetThreadAffinityMask там не оказалось,
// потому и пришлось его определять самому)
public static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
// Тут же определяем через интерфейс нужную нам библиотечную функцию
public interface ThreadSupport extends Library {
int SetThreadAffinityMask(Pointer hThread, int dwThreadAffinityMask);
}
}
Теперь для решения нашей основной задачи нужно просто сделать следующий вызов в потоке который мы хотим повесить на нужное нам ядр:
// Маска определяет на какие ядра мы вешаем наш поток // Внутри важно двоичное представление числа, // и так как 0x00000007 в двоичной системе это 00000111 // значит мы хотим повесить выполнение нашего потока на три ядра // по порядку младших битов. // К примеру если бы мы хотели задействовать первое и третье ядро // (нумерация условна, зависит от системы) нужно было бызапихать в качестве маски 00000101 – те 0x00000005 int coreMask = 0x00000007; int flag = KernelThreadSupport.threadSupport.SetThreadAffinityMask( // вызываем указатель дескриптора текущего потока KernelThreadSupport.kernel32.GetCurrentThread().getPointer(), // устанавливаем нужную маску coreMask);
В переменной flag мы увидим предыдущее значение маски.
Вот собственно и все. Результаты легко можно увидеть в диспетчере задач.
К примеру в моем случае при 3 разных вариантах я видел следующее –
Для маски 0x00000002 (00000010)
Для маски 0x00000007 (00000111)
Для маски 0x00000006 (00000110)