Синхронизированные потоки с семафорами
Я пытаюсь синхронизировать некоторые потоки с помощью семафоров. Цель состоит в том, чтобы многократно печатать последовательность из 1 (8 раз), 2 (4 раза), 4 (2 раза) и 8 (1 раз) в этом порядке. Моя программа работает правильно, пока она не завершится примерно на 90%, а затем она испортит 2 и 4. Я не могу понять на всю жизнь, что может быть причиной проблемы. Какие-либо предложения?
public class ThreadSync
{
private static int count = 100;
private static Semaphore printSomeOnes = new Semaphore(1);
private static Semaphore printSomeTwos = new Semaphore(0);
private static Semaphore printSomeFours = new Semaphore(0);
private static Semaphore printSomeEights = new Semaphore(0);
private static boolean runFlag = true;
public static void main( String[] args ) {
// create and start each runnable
Runnable task1 = new TaskPrint1();
Runnable task2 = new TaskPrint2();
Runnable task3 = new TaskPrint4();
Runnable task4 = new TaskPrint8();
Thread thread1 = new Thread( task1 );
Thread thread2 = new Thread( task2 );
Thread thread3 = new Thread( task3 );
Thread thread4 = new Thread( task4 );
thread1.start();
thread2.start();
thread3.start();
thread4.start();
// Let them run for 500ms
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// put up the stop sign
runFlag=false;
thread4.interrupt();
thread3.interrupt();
thread2.interrupt();
thread1.interrupt();
}
public static class TaskPrint1 implements Runnable
{
public void run(){
while (runFlag) {
for(int i = 0; i < count; i++){
if(i % 8 == 0){
try {
printSomeOnes.acquire();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.printf( "%s\n", "1");
if(i % 8 == 0){
printSomeTwos.release();
}
}
}
}
}
public static class TaskPrint2 implements Runnable
{
public void run(){
while (runFlag) {
for(int i = 0; i < count; i++){
if(i % 4 == 0){
try {
printSomeTwos.acquire();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.printf( "%s\n", "2");
if(i % 4 == 0){
printSomeFours.release();
}
}
}
}
}
public static class TaskPrint4 implements Runnable
{
public void run(){
while (runFlag) {
for(int i = 0; i < count; i++){
if(i % 2 == 0){
try {
printSomeFours.acquire();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.printf( "%s\n", "4");
if(i % 2 == 0){
printSomeEights.release();
}
}
}
}
}
public static class TaskPrint8 implements Runnable
{
public void run(){
while (runFlag) {
for(int i = 0; i < count; i++){
try {
printSomeEights.acquire();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.printf( "%s\n", "8");
printSomeOnes.release();
}
}
}
}
}
1 ответ
Некоторые изменения, которые я сделал:
Удалить runFlag
использование Thread.currentThread().isInterrupted()
, который является лучшим способом справиться с этой ситуацией. И когда нибудь InterruptedException
происходит только сброс флага прерывания для потока, чтобы на него воздействовал код более высокого порядка. Как:
try {
printSomeOnes.acquire();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
Здесь когда-либо InterruptedException
происходит просто сбросить флаг так, чтобыwhile (!Thread.currentThread().isInterrupted()) {
может действовать соответственно. Каким образом мы должны иметь дело с этим. Надеюсь, поможет.
public class ThreadSync {
private static int count = 100;
private static Semaphore printSomeOnes = new Semaphore(1);
private static Semaphore printSomeTwos = new Semaphore(0);
private static Semaphore printSomeFours = new Semaphore(0);
private static Semaphore printSomeEights = new Semaphore(0);
private static volatile boolean runFlag = true;
public static void main(String[] args) {
// create and start each runnable
Runnable task1 = new TaskPrint1();
Runnable task2 = new TaskPrint2();
Runnable task3 = new TaskPrint4();
Runnable task4 = new TaskPrint8();
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
Thread thread3 = new Thread(task3);
Thread thread4 = new Thread(task4);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
// Let them run for 500ms
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
// put up the stop sign
// runFlag=false;
thread4.interrupt();
thread3.interrupt();
thread2.interrupt();
thread1.interrupt();
}
public static class TaskPrint1 implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
for (int i = 0; i < count; i++) {
if (i % 8 == 0) {
try {
printSomeOnes.acquire();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
}
System.out.printf("%s\n", "1");
if (i % 8 == 0) {
printSomeTwos.release();
}
}
}
}
}
public static class TaskPrint2 implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
for (int i = 0; i < count; i++) {
if (i % 4 == 0) {
try {
printSomeTwos.acquire();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
}
System.out.printf("%s\n", "2");
if (i % 4 == 0) {
printSomeFours.release();
}
}
}
}
}
public static class TaskPrint4 implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
for (int i = 0; i < count; i++) {
if (i % 2 == 0) {
try {
printSomeFours.acquire();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
}
System.out.printf("%s\n", "4");
if (i % 2 == 0) {
printSomeEights.release();
}
}
}
}
}
public static class TaskPrint8 implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
for (int i = 0; i < count; i++) {
try {
printSomeEights.acquire();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
System.out.printf("%s\n", "8");
printSomeOnes.release();
}
}
}
}
}