我正在阅读有关线程安全性和synchronized
关键字的信息,但我很难弄清楚它是如何正确实现的。
我的情况是Thread
A 将数据保存到Buffer
,Thread
B 读取数据并保存到数据库。
如何使用以下代码实现线程安全?
通过线程安全,我的意思是Thread
B不会开始直到Thread
完成它的工作,同样适用于Thread
A。
public class Main {
public static void main(String args[]) throws InterruptedException {
LinkedBlockingQueue<Document> queue = new LinkedBlockingQueue<>();
ProducerThread mProducer = new ProducerThread(queue);
ConsumerThread mConsumer = new ConsumerThread(queue);
new Thread(mProducer).start();
new Thread(mConsumer).start();
}
}
-
public class ProducerThread implements Runnable {
private LinkedBlockingQueue<Document> queue;
public ProducerThread(LinkedBlockingQueue<Document> queue) {
this.queue = queue;
}
@Override
public void run() {
while(true) {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Document document = new Document("timeAdded", timestamp);
try {
queue.put(document);
System.out.println("Document added " + document.toString());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
-
public class ConsumerThread implements Runnable {
private LinkedBlockingQueue<Document> queue;
private Database mDatabase;
public ConsumerThread(LinkedBlockingQueue<Document> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
Document doc;
mDatabase = Database.getInstance();
if (Client.isAlive()) {
while (queue.take() != null) {
mDatabase.insert(queue.take());
// Thread.sleep(10);
System.out.println("Document consumed " + queue.take().toString());
if (!Client.isAlive()) {
wait();
Client.reconnect();
}
}
} else {
wait();
}
} catch(InterruptedException | IllegalMonitorStateException e){
e.printStackTrace();
}
}
}
我得到以下输出
> Document added{{timeAdded=2018-04-22 13:20:27.88}}
> Document{{timeAdded=2018-04-22 13:20:27.88}} Document added
> Document{{timeAdded=2018-04-22 13:20:28.881}} Document added
> Document{{timeAdded=2018-04-22 13:20:29.882}} Document added
> Document{{timeAdded=2018-04-22 13:20:30.882}} Consumed
> Document{{timeAdded=2018-04-22 13:20:30.882}} Document added
> Document{{timeAdded=2018-04-22 13:20:31.883}} Document added
> Document{{timeAdded=2018-04-22 13:20:32.883}} Consumed
> Document{{timeAdded=2018-04-22 13:20:33.884}} Document added
> Document{{timeAdded=2018-04-22 13:20:33.884}} Document added
> Document{{timeAdded=2018-04-22 13:20:34.885}} Document added
> Document{{timeAdded=2018-04-22 13:20:35.885}} Document added
> Document{{timeAdded=2018-04-22 13:20:36.886}} Consumed
> Document{{timeAdded=2018-04-22 13:20:36.886}} Document added
答案 0 :(得分:1)
我不知道这是否有帮助,但我会写一个名为 ProductionProcess 的第三类或类似的东西......
简短的附加说明: ProductionClass 包含存储单个 Document 对象的队列。 Producer 线程开始生成&#34;生成&#34;对象只要队列(当前大小为10)已满。每当此队列中的一个插槽空闲时,因为 Consumer 线程删除了一个 Document 对象。 Producer 线程接收信号并开始生成&#34;再次记录对象,直到队列已满。完整的源代码应该是线程安全的。
public class ProductionProcess
{
private static final int CAPACITY;
private final Queue QUEUE;
private final Lock LOCK;
private final Condition BUFFER_FULL;
private final Condition BUFFER_EMPTY;
static
{
CAPACITY = 10;
}
ProductionProcess()
{
this.QUEUE = new LinkedList <Document> ();
this.LOCK = new ReentrantLock();
this.BUFFER_FULL = this.LOCK.newCondition();
this.BUFFER_EMPTY = this.LOCK.newCondition();
}
public void produce() throws InterruptedException
{
this.LOCK.lock();
try
{
while(ProductionProcess.CAPACITY == this.QUEUE.size())
{
System.out.println(Thread.currentThread().getName() + " : Buffer is full, waiting!");
this.BUFFER_FULL.await();
}
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Document document = new Document("timeAdded", timestamp);
if(true == this.QUEUE.offer(document))
{
System.out.printf("Added to queue: " + document);
this.BUFFER_EMPTY.signalAll();
}
}
finally
{
this.LOCK.unlock();
}
}
public void receive() throws InterruptedException
{
this.LOCK.lock();
try
{
Database mDatabase = Database.getInstance();
while(0 == this.QUEUE.size())
{
System.out.println(Thread.currentThread().getName() + " : Buffer is empty, waiting!");
this.BUFFER_EMPTY.await();
}
Document mDocument = (Document) this.QUEUE.poll());
if(null != mDocument)
{
mDatabase.insert(mDocument);
System.out.printf("Consumed from queue: " + document);
System.out.println(Thread.currentThread().getName() + " : Signalling that buffer may be empty now");
this.BUFFER_FULL.signalAll();
}
}
finally
{
this.LOCK.unlock();
}
}
}
之后使用它就像这样...
ProductionProcess process = new ProductionProcess();
Runnable runnableProducer = new Runnable() {
@Override public void run()
{
while(true)
{
try
{
process.produce();
Thread.sleep(1000);
}
catch(InterruptedException exc)
{
exc.printStackTrace();
}
}
}
}
Runnable runnableConsumer = new Runnable() {
@Override public void run()
{
while(true)
{
try
{
process.receive();
Thread.sleep(1000);
}
catch(InterruptedException exc)
{
exc.printStackTrace();
}
}
}
}
new Thread(runnableProducer).start();
new Thread(runnableConsumer).start();
我没有对它进行广泛的测试,但它应该可行。如果它不起作用只是评论它... 此外,如果你能说德语,请注意这不是我的代码link。