本文涉及到的代码可以在我的github中找到。
题目一:
现有一程序中的Test100类中的代码在不断的产生数据,然后交给TestDo.doSome()方法去处理,就好像生产者在不断地产生数据,消费者在不断消费数据。请编写程序模拟10个线程来消费生产者产生的数据,这些消费者调用数据,只有上一一个消费者消费完之后,下一个消费者才能消费数据,保证消费者线程拿到的数据时有序的。
拿到题目我们首先不要着急写代码,而是要进行题目的逻辑分析。首先我们可以用一个循环启动10个线程,每个线程内部执行的逻辑都是调用一个doSome()方法消费数据。按照题目要求,我们需要选择一个阻塞队列来充当生产者和消费者之间数据交换的容器。其实从这里我们可以体会到,(阻塞队列有点支持线程间通信的作用),即生产者产生数据放入队列,消费者从队列取出数据,而且我们要保证每个每次只有一个队列可以取到,这样按照几种阻塞队列的特点,我们可以选择SynchronoutQueue。另外,我们还要有一个锁,保证一个时间只有一个消费者在消费。
下面是代码:
import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;
public class Test100
{
public static void main(String[] args)
{
//queue的作用是充当生产者和消费者之间数据交换的容器
SynchronousQueue<String> queue = new SynchronousQueue<>();
//signal的作用是决定线程执行的秩序
Semaphore signal = new Semaphore(1);
for (int i = 0; i < 10; i++)
{
new Thread(new Runnable()
{
@Override
public void run()
{
// TODO Auto-generated method stub
try
{
signal.acquire();//得到通行证
String input = queue.take();//取出数据
String output = TestDo.doSome(input);
System.out.println(Thread.currentThread().getName() + " : " + output);
signal.release();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
for(int i = 0;i<10;i++)
{
try
{
queue.put(i+"");
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class TestDo
{
public static String doSome(String input)
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
String output = input + ":" + (System.currentTimeMillis() / 1000);
return output;
}
}
运行结果:
Thread-0 : 0:1471068136
Thread-1 : 1:1471068137
Thread-2 : 2:1471068138
Thread-3 : 3:1471068139
Thread-7 : 4:1471068140
Thread-4 : 5:1471068141
Thread-6 : 6:1471068142
Thread-5 : 7:1471068143
Thread-8 : 8:1471068144
Thread-9 : 9:1471068145