java 同步器

来源:互联网 发布:pda扫描枪网络设置 编辑:程序博客网 时间:2024/05/09 21:49

信号量

如果学过操作系统这门课应该对信号量这个名词相当熟悉,其中Mutex互斥锁更是操作系统中用来访问临界资源的用例经典。

其实包括p操作和v操作

void p(s){

while(s<=0);

s--;

}

void V(s){

s++;

}

倒计时门栓

让一个线程集等待直到计数变为0,倒计时门栓是一次性的。一旦计数器为0,就不能再用了

当一个或者 多个线程需要等待直到指定数目的事件发生时使用。

一个人要完成一些任务,但是需要些数据,此时这个人准备好后(就绪)在门外等着,另外几个人在里面准备数据。这个人数取决于new门栓是的参数,当数据准备好后调用countdown(),那个要完成要任务的就可以开始工作啦、跟下面的障栅是几乎一样的。所以看下面就应该能明白我要说的了。

障栅

很形象的名字,可以把线程比喻成一队运动员,当最先一个运动员跑到终点时先等待后边的。当所有运动员都跑到这个障栅时,然后再一起跑。期间如果任何一个线程在等待时候离开的障栅,会破坏障栅,其它线程会报异常错误。
书上说使用场景 是当大量的线程需要在它们结果可用之前完成时。
package test;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.Phaser;public class Demo {private static int num = 0;public static void main(String[] Args) {new Demo().test();}private void test() {Runnable comtask = new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("完成啦完成啦");}};CyclicBarrier cb = new CyclicBarrier(3, comtask);thread t1 = new thread(cb);thread t2 = new thread(cb);thread t3 = new thread(cb);t1.start();t2.start();t3.start();System.out.println(cb.getNumberWaiting());}class thread extends Thread {private CyclicBarrier cb;public thread(CyclicBarrier cb) {super();this.cb = cb;}@Overridepublic void run() {// TODO Auto-generated method stubtry {cb.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (BrokenBarrierException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

输出结果:
完成啦完成啦
0
障栅是可以重用的,之后调用 cb.reset();即可完成重置,而倒计时门栓只可以用一次。

交换器

交换嘛,两个线程在同一个缓冲区的两个实例上工作的时候,就可以用交换器,如,一个人在做饭,一个人在吃饭。那么这个碗就是缓冲区,做完了,吃完了。之后交换这个碗。就是一个线程在消耗数据,一个在准备数据。又比如一个线程在根据数据进行计算,一个线程在收集新的数据。
package test;import java.util.concurrent.Exchanger;public class Demo {private static int num = 0;public static void main(String[] Args) {new Demo().test();}private void test() {Exchanger<Integer> ec = new Exchanger<Integer>();threadcook tc = new threadcook(ec);threadeat te = new threadeat(ec);tc.start();te.start();}class threadcook extends Thread {private Exchanger<Integer> ec;public threadcook(Exchanger<Integer> ec) {super();this.ec = ec;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {int result = 0;for (int i = 0; i < 100; i++) {result += i;}try {ec.exchange(result);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("我是做饭的内个~:" + result);}}}class threadeat extends Thread {private Exchanger<Integer> ec;public threadeat(Exchanger<Integer> ec) {super();this.ec = ec;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {int result = 0;try {ec.exchange(result);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("我是吃饭的内个~:" + result);}}}}

结果:
我是做饭的内个~:4950
我是吃饭的内个~:0
我是吃饭的内个~:0
我是做饭的内个~:4950
我是吃饭的内个~:0
我是做饭的内个~:4950
我是吃饭的内个~:0
我是做饭的内个~:4950
我是吃饭的内个~:0
我是吃饭的内个~:0
我是做饭的内个~:4950
我是做饭的内个~:4950
我是吃饭的内个~:0
我是做饭的内个~:4950
我是吃饭的内个~:0
我是做饭的内个~:4950
我是吃饭的内个~:0
我是做饭的内个~:4950

好吧要吃饭的那个估计已经饿死了。。。那么问题出在哪呢。。

哦这个点找错了,交换之后获得的对象是exchange()这个方法的返回值,并不会重新对result赋值。所以改过之后 

package test;import java.util.concurrent.Exchanger;import javax.xml.ws.spi.Invoker;public class Demo {private static int num = 0;public static void main(String[] Args) {new Demo().test();}private void test() {Exchanger<Integer> ec = new Exchanger<Integer>();threadcook tc = new threadcook(ec);threadeat te = new threadeat(ec);tc.start();te.start();}class threadcook extends Thread {private Exchanger<Integer> ec;public threadcook(Exchanger<Integer> ec) {super();this.ec = ec;}@Overridepublic void run() {// TODO Auto-generated method stubint result = 0;for (int i = 0; i < 100; i++) {result += i;}try {System.out.println("我是做饭的内个~:" + ec.exchange(result));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}class threadeat extends Thread {private Exchanger<Integer> ec;public threadeat(Exchanger<Integer> ec) {super();this.ec = ec;}@Overridepublic void run() {// TODO Auto-generated method stubint result = 0;try {System.out.println("我是吃饭的内个~:" + ec.exchange(result));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

结果 :

我是吃饭的内个~:4950
我是做饭的内个~:0

这就对 了~~


同步队列

跟交换器很像,不过这次是单向的,一个线程在向队列里边压数据 ,另一个在取,不过这个交换器的不同就是这个可以是多个线程之间的协作,不像交换器只能支持两个线程。
为了方便我们将上一个例子改一下就好了啦。
为了体现出是队列,我们取100次却只压入10次队列。

package test;import java.util.concurrent.Exchanger;import java.util.concurrent.SynchronousQueue;import javax.xml.ws.spi.Invoker;public class Demo {private static int num = 0;public static void main(String[] Args) {new Demo().test();}private void test() {SynchronousQueue<Integer> sq = new SynchronousQueue<Integer>();threadcook tc = new threadcook(sq);threadeat te = new threadeat(sq);tc.start();te.start();}class threadcook extends Thread {private SynchronousQueue<Integer> sq;public threadcook(SynchronousQueue<Integer> sq) {super();this.sq = sq;}@Overridepublic void run() {// TODO Auto-generated method stubfor (int i = 0; i < 100; i++) {try {System.out.println(sq.take());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}class threadeat extends Thread {private SynchronousQueue<Integer> sq;public threadeat(SynchronousQueue<Integer> sq) {super();this.sq = sq;}@Overridepublic void run() {// TODO Auto-generated method stubfor (int i = 0; i < 10; i++) {try {sq.put(i);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}
结果:
0
1
2
3
4
5
6
7
8
9
喵~跟预计的一样。好的呢,今天就到这里了。





0 0
原创粉丝点击