java 同步器

信号量

如果学过操作系统这门课应该对信号量这个名词相当熟悉,其中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() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.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;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				cb.await();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				// TODO Auto-generated catch block
				e.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;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while (true) {
				int result = 0;
				for (int i = 0; i < 100; i++) {
					result += i;
				}
				try {
					ec.exchange(result);

				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("我是做饭的内个~:" + result);
			}

		}
	}

	class threadeat extends Thread {
		private Exchanger<Integer> ec;

		public threadeat(Exchanger<Integer> ec) {
			super();
			this.ec = ec;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while (true) {
				int result = 0;
				try {
					ec.exchange(result);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.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;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			int 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 block
				e.printStackTrace();

			}
		}
	}

	class threadeat extends Thread {
		private Exchanger<Integer> ec;

		public threadeat(Exchanger<Integer> ec) {
			super();
			this.ec = ec;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub

			int result = 0;
			try {
				System.out.println("我是吃饭的内个~:" + ec.exchange(result));
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.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;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			for (int i = 0; i < 100; i++) {
				try {
					System.out.println(sq.take());
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		}
	}

	class threadeat extends Thread {
		private SynchronousQueue<Integer> sq;

		public threadeat(SynchronousQueue<Integer> sq) {
			super();
			this.sq = sq;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			for (int i = 0; i < 10; i++) {
				try {
					sq.put(i);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		}
	}

}
结果:
0
1
2
3
4
5
6
7
8
9
喵~跟预计的一样。好的呢,今天就到这里了。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值