java - Looking for a solid explanation on how aquire and release work with semaphores to sync threads -
i trying manipulate programme print ":---)))))" repeatedly. understand semaphore way of controlling threads, , acquire acquires permit (reads) , release returns permit semaphore. (writes)
i've tried manipulating number of permits when initializing semaphores, not understanding how sync them because can't figure out how semaphores operate how acquire , release.
i looking helpful explanation pertains java in context of using semaphores, acquire , release , how work set threads "in sync"
import java.lang.thread; import java.util.concurrent.*; public class threadsync { private static boolean runflag = true; private static semaphore canprintc = new semaphore(1); private static semaphore canprintd = new semaphore(0); private static semaphore canprintp = new semaphore(0); public static void main(string [] args) { // create , start each runnable runnable task1 = new taskprintc(); runnable task2 = new taskprintd(); runnable task3 = new taskprintp(); thread thread1 = new thread(task1); thread thread2 = new thread(task2); thread thread3 = new thread(task3); thread1.start(); thread2.start(); thread3.start(); // allow them run 500 ms seek { thread.sleep(500); } grab (interruptedexception e) { e.printstacktrace(); } runflag = false; thread3.interrupt(); thread2.interrupt(); thread1.interrupt(); } public static class taskprintc implements runnable { public void run() { while (runflag) { seek { canprintc.acquire(); } grab (interruptedexception ex) { ex.printstacktrace(); } system.out.printf("%s", ":"); canprintd.release(); } } } public static class taskprintd implements runnable { public void run() { while (runflag) { seek { canprintd.acquire(); } grab (interruptedexception ex) { ex.printstacktrace(); } system.out.printf("%s", "-"); canprintp.release(); } } } public static class taskprintp implements runnable { public void run() { while (runflag) { seek { canprintp.acquire(); } grab (interruptedexception ex) { ex.printstacktrace(); } system.out.printf("%s", ")"); canprintc.release(); } } }
}
threads execute tasks , semaphores can help allow tasks (or runnable objects) know each other's state (e.g. task waits input task b , task b can signal task input available). difference between task , thread important.
to stress point, have taken illustration , made 1 runnable class performs task of printing character number of times (configured via variables in constructor). mimic serialized behavior (tasks run after each other), runnable aware of next runnable should perform print task.
to finish illustration ensured thread executing main-method aware of when tasks have completed, programme stops @ proper time. countdownlatch used in case (a countdownlatch simple variation of semaphore).
the illustration below might bit hard understand, shows practices (re-use code, using stop-flag instead of interrupt, utilize executor run tasks, cleanup , stop tasks in case of error). shows how semaphores can orchestrate execution of tasks.
import java.util.arraylist; import java.util.list; import java.util.concurrent.countdownlatch; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import java.util.concurrent.semaphore; import java.util.concurrent.timeunit; import java.util.concurrent.atomic.atomicinteger; public class chainedsemaphoretasks { // amount of times chained tasks executed. static int max_chained_loops = 3; // helper allow main-thread know when chained loops have been executed. final static countdownlatch max_loops_reached = new countdownlatch(1); public static void main(string[] args) { string printchars = ":-)"; int[] repeatchars = { 1, 3, 5}; list<chainedtask> tasks = buildtasks(printchars, repeatchars); executorservice executor = executors.newcachedthreadpool(); (chainedtask task : tasks) { executor.execute(task); } seek { // trigger first task start running. tasks.get(0).triggerprinttask(); // wait loop complete, not long. if (!max_loops_reached.await(5000l, timeunit.milliseconds)) { throw new runtimeexception("chained tasks loop did not finish within timeout."); } long waitstart = system.currenttimemillis(); executor.shutdown(); if (executor.awaittermination(1000l, timeunit.milliseconds)) { system.out.println("all tasks stopped within " + (system.currenttimemillis() - waitstart) + " ms."); } else { throw new runtimeexception("not chained tasks stopped within timeout."); } } grab (exception e) { e.printstacktrace(); // cleanup seek { tasks.get(0).stop(); } grab (exception e2) { e2.printstacktrace(); } executor.shutdownnow(); } } static list<chainedtask> buildtasks(string printchars, int[] repeatchars) { list<chainedtask> tasks = new arraylist<chainedtask>(); int maxtasks = printchars.length(); if (maxtasks != repeatchars.length) { throw new illegalargumentexception("amount of repeats per pritn character must match amount of characters."); } (int = 0; < maxtasks; i++) { chainedtask task = new chainedtask(printchars.charat(i), repeatchars[i]); tasks.add(task); if (i > 0) { tasks.get(i - 1).setnexttask(task); } } // create lastly task trigger first task - creates endless loop. tasks.get(maxtasks - 1).setnexttask(tasks.get(0)); tasks.get(maxtasks - 1).setlasttask(true); homecoming tasks; } static atomicinteger chainedloopscount = new atomicinteger(); static class chainedtask implements runnable { // semaphore trigger execution semaphore performtask = new semaphore(0); // if stop true, task must finish. // stop must volatile ensure updated value visible. volatile boolean stop = false; // lastly task responsible stopping execution boolean lasttask; // next task run after task. chainedtask nexttask; char printchar; int repeatamount; chainedtask(char printchar, int repeatamount) { this.printchar = printchar; this.repeatamount = repeatamount; system.out.println("created " + printchar + " / " + repeatamount); } void triggerprinttask() { performtask.release(repeatamount); } void stop() { // first indicate stop stop = true; // release permit pickup stop sign. performtask.release(); // stop next task, unless lastly task if (!islasttask()) { getnexttask().stop(); } } @override public void run() { seek { while (!stop) { runtask(); } } grab (exception e) { e.printstacktrace(); } system.out.println("stopped " + printchar + " / " + repeatamount); } void runtask() throws exception { // wait our turn performtask.acquire(); // must check 'stop' after getting permit, see stop-method: // first stop set true , permit released. if (stop) { return; } // print text loop-amount { system.out.print(printchar); } while (performtask.tryacquire()); if (islasttask()) { system.out.println(); // check if should stop if (chainedloopscount.incrementandget() >= max_chained_loops) { // since lastly task, next task first task. // stopping first task phone call stop-method on tasks, including one. getnexttask().stop(); // signal main-thread done. max_loops_reached.countdown(); } // sleep long time test happens when lastly task hangs. // should trigger "cleanup" code in main method. // thread.sleep(10000); } // trigger next chained task run // has no effect if next chained task stopped getnexttask().triggerprinttask(); } void setnexttask(chainedtask nexttask) { this.nexttask = nexttask; } chainedtask getnexttask() { homecoming nexttask; } void setlasttask(boolean lasttask) { this.lasttask = lasttask; } boolean islasttask() { homecoming lasttask; } } }
java multithreading semaphore
No comments:
Post a Comment