话外语:我胡汉三又回来啦!!!
----------------------------------------------------------------------------------------------------------------------------------
Java中线程同步有一个典型的问题就是“生产者消费者”问题。
用两个线程模拟存票售票过程:假定开始售票处并没有票,一个线程往里面存票,另一个线程则往外售票。
新建一个票类对象,让存票和售票线程都访问它。(两个线程共享一个数据并对其进行操作)
package multi_thread;
public class ProducerAndConsumer {
public static void main(String[] args) {
// TODO Auto-generated method stub
Tickets t = new Tickets(10);
new Producer(t).start();
new Consumer(t).start();
}
}
class Tickets{
int number =0; //票号
int size; //总票数
boolean available = false; //表示目前是否有票可售
public Tickets(int size) {
this.size = size;
}
}
class Producer extends Thread{
Tickets t = null;
public Producer(Tickets t ) {
this.t = t;
}
public void run() {
while( t.number < t.size) {
System.out.println("Producer puts ticket "+(++t.number));
t.available = true;
}
}
}
class Consumer extends Thread{
Tickets t = null;
int i=0;
public Consumer (Tickets t ) {
this.t = t;
}
public void run() {
while( i< t.size) {
if(t.available==true && i<=t.number)
System.out.println("Consumer buys ticket "+(++i));
if(i==t.number)
t.available = false;
}
}
}
运行结果:
Producer puts ticket 1
Producer puts ticket 2
Producer puts ticket 3
Producer puts ticket 4
Producer puts ticket 5
Producer puts ticket 6
Producer puts ticket 7
Producer puts ticket 8
Producer puts ticket 9
Producer puts ticket 10
Consumer buys ticket 1
Consumer buys ticket 2
Consumer buys ticket 3
Consumer buys ticket 4
Consumer buys ticket 5
Consumer buys ticket 6
Consumer buys ticket 7
Consumer buys ticket 8
Consumer buys ticket 9
Consumer buys ticket 10
运行结果是先把票全部生产完然后再售票。(为啥不是边生产边售票呢???)
然后朕试着把调用生产票和消费票的顺序改变了一下,就变成边生产边售票了。。。
new Producer(t).start();
new Consumer(t).start();
变成
new Consumer(t).start();
new Producer(t).start();
具体代码见下:
package multi_thread;
public class ProducerAndConsumer {
public static void main(String[] args) {
// TODO Auto-generated method stub
Tickets t = new Tickets(10);
new Consumer(t).start();
new Producer(t).start();
}
}
class Tickets{
int number =0; //票号
int size; //总票数
boolean available = false; //表示目前是否有票可售
public Tickets(int size) {
this.size = size;
}
}
class Producer extends Thread{
Tickets t = null;
public Producer(Tickets t ) {
this.t = t;
}
public void run() {
while( t.number < t.size) {
System.out.println("Producer puts ticket "+(++t.number));
t.available = true;
}
}
}
class Consumer extends Thread{
Tickets t = null;
int i=0;
public Consumer (Tickets t ) {
this.t = t;
}
public void run() {
while( i< t.size) {
if(t.available==true && i<=t.number)
System.out.println("Consumer buys ticket "+(++i));
if(i==t.number)
t.available = false;
}
}
}
运行结果:(运行结果也是随机的,每次都不一样,但总是先有票才能后售票)
Producer puts ticket 1
Producer puts ticket 2
Consumer buys ticket 1
Producer puts ticket 3
Consumer buys ticket 2
Producer puts ticket 4
Consumer buys ticket 3
Producer puts ticket 5
Consumer buys ticket 4
Producer puts ticket 6
Producer puts ticket 7
Producer puts ticket 8
Producer puts ticket 9
Producer puts ticket 10
Consumer buys ticket 5
Consumer buys ticket 6
Consumer buys ticket 7
Consumer buys ticket 8
Consumer buys ticket 9
Consumer buys ticket 10
以上两端代码运行结果不一样,应该是和CPU的调度有关吧!
第一段代码由于生产者线程在前面,所以CPU资源就先一直给它占据了。由于它生产完票的时间也没有很长啦(就10张票),所以它就生产完了,然后再售票!(为了证明我的说法是正确的,我把生产的票数改成了100,果真,就变成生产和消费交错进行了。因为100张票还是挺多的,CPU资源也不可能一直都给生产者线程一个人占据,就会出现交错进行的情况)
而第二段代码,消费者在前面,它也确实是先执行的。但是在它执行期间由于无票可售,所以它没有输出语句到屏幕(它在执行,只是我们没有看到)。等它执行一段时间后,就生产者执行,然后就出现这样的结果了。
Java对线程同步其实是提供了方法的,关键字synchronized,实现互斥。
synchronized(对象){代码段}
synchronized的功能是:首先判断对象的锁是否在,如果在就获得锁,然后就可以执行紧随其后的代码段;如果对象的锁不在(已经被其他线程拿走),就进入等待状态,直到获得锁。
当被synchronized限定的代码段执行完,就释放锁。