我有一个包含作家和读者的程序,他们的访问权限由监视器控制。
所以,这本来应该饿死,但我遇到了僵局。我想知道为什么然后我记得我放了另一个锁,我认为在读取方法内部读取内部是不必要的,以保护我的全局变量不会出现不一致。我认为它不会造成任何死锁,因为我可以在没有发生任何死锁的情况下运行10000次线程,但是当我不得不进行实验室演示时,我认为它在第10010个线程中陷入僵局。我不明白为什么它会这样做。此外,我没想到它会饿死,但显然它应该是。
我的问题是:那些负责死锁的多级锁吗?如果没有,是什么导致了这个?!
import java.io.*;
import java.io.IOException;
import java.util.*;
public class Writer extends Thread{
private int number;
public Writer(int number)
{
this.number = number;
}
public int getNumber()
{
return number;
}
public static void Write(String filename){
try {
String content = RandomString();
File f = new File(filename);
if (!f.exists())
{
f.createNewFile();
}
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("Task1out.txt", true)));
out.println(content);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static String RandomString(){
String chars = new String("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
int n = chars.length();
String randomString = new String();
Random r = new Random();
for (int i=0; i<100; i++)
{
randomString = randomString + chars.charAt(r.nextInt(n));
}
System.out.println("RandomString() generated: " + randomString);
return randomString;
}
public void run(){
try{
//FileControl fc = new FileControl();
int number = this.getNumber();
for(int i = 0; i <1000; i++) //CHANGE IT TO 1000
{
main.fc.WriterEntry(number);
//write file random characters (must append)
Write("Task1out.txt");
main.fc.WriterExit(number);
}
} catch(InterruptedException e)
{
System.out.println("Interrupted Exception caught");
}
}
}
这是作家班。
import java.io.BufferedWriter;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Reader extends Thread{
private int number;
public Reader(int number)
{
this.number = number;
}
public int getNumber()
{
return number;
}
public static synchronized void Read(String filename)throws InterruptedException{
BufferedReader br = null;
main.lock.lock(); //lock
try{
try {
String line;
char[] chars = new char[100];
int readIndex2 = 0;
int addToIndex = 0;
br = new BufferedReader(new FileReader(filename));
int initialReadIndex = main.getIndex();
System.out.println("initial read index: " + initialReadIndex);
while ((line = br.readLine()) != null && readIndex2 < initialReadIndex+100 && addToIndex < 100) {
for(int i = 0; i< 100; i++)
{
if (initialReadIndex == readIndex2 || initialReadIndex < readIndex2)
{
if(line.length() > addToIndex)
{
chars[i] = line.charAt(i);
addToIndex++;
}
}
else
{
readIndex2++;
}
}
System.out.println(chars);
}
if(line == null)
{
System.out.println("nothing to read");
}
main.incrementIndex(addToIndex);
System.out.println("current read index: " + (initialReadIndex + addToIndex));
} catch (IOException e) {
e.printStackTrace();
System.out.println("buffered reader exception");
} finally {
try {
if (br != null)
{
br.close();
}
} catch (IOException ex) {
ex.printStackTrace();
System.out.println("exception during closing");
}
}
}finally{
main.lock.unlock(); //lock
}
}
public void run(){
try{
//FileControl fc = new FileControl();
int number = this.getNumber();
for(int i = 0; i <1000; i++) //CHANGE IT TO 1000
{
main.fc.ReaderEntry(number);
//read file
Read("Task1out.txt");
main.fc.ReaderExit(number);
}
} catch(InterruptedException e)
{
System.out.println("Interrupted Exception caught");
}
}
}
这是读者类。
import java.io.BufferedWriter;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.FileReader;
import java.io.IOException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class main{
public static FileControl fc = new FileControl();
final static Lock lock = new ReentrantLock();
public static int readIndex;
public static void incrementIndex(int increment) {
readIndex = readIndex + increment;
}
public static int getIndex()
{
return readIndex;
}
public static void main(String[] args) throws InterruptedException {
Writer [] writer = new Writer[10];
Reader [] reader = new Reader[10];
for(int i = 0; i < 10; i++)
{
reader[i] = new Reader(i);
writer[i] = new Writer(i);
//creating readers and writers
}
for(int i = 0; i < 10; i++)
{
//anonymous threads
//(new Thread(new Writer())).start();
//(new Thread(new Reader())).start();
reader[i].start();
writer[i].start();
}
for(int i = 0; i < 10; i++)
{
try{
reader[i].join();
writer[i].join();
} catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
这是主要的课程。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FileControl {
final Lock lock = new ReentrantLock();
final Condition writers = lock.newCondition();
final Condition readers = lock.newCondition();
int activereaders = 0;
int waitingwriters = 0;
boolean writing = false;
public void WriterEntry(int number)throws InterruptedException{
lock.lock();
try{
if(writing == true || activereaders > 0){
waitingwriters++;
System.out.println("Writer thread " + number + " : waiting to write");
writers.await();
waitingwriters--;
}
System.out.println("Writer thread " + number + " : ready to write");
writing = true;
}
finally{
lock.unlock();
}
}
public void WriterExit(int number)throws InterruptedException{
lock.lock();
try{
System.out.println("Writer thread " + number + " : finished to write");
System.out.println("writers " + waitingwriters + "readers " + activereaders); //test
if(waitingwriters > 0)
writers.signal();
else{
writing = false;
readers.signal();
}
}
finally{
lock.unlock();
}
}
public void ReaderEntry(int number)throws InterruptedException{
lock.lock();
try{
if(writing == true || waitingwriters > 0){ //remove activereaders > 0
System.out.println("Reader thread " + number + " : waiting to read");
readers.await();
activereaders++;
}
System.out.println("Reader thread " + number + " : ready to read");
}
finally{
lock.unlock();
}
}
public void ReaderExit(int number)throws InterruptedException{
lock.lock();
try{
activereaders--;
System.out.println("Reader thread " + number + " : finished to read");
System.out.println("writers " + waitingwriters + "readers " + activereaders); //test
if(activereaders == 0)
{
if(waitingwriters > 0)
{
writers.signal();
}
else
{
readers.signal();
}
}
}
finally{
lock.unlock();
}
}
}
这是监视器。
答案 0 :(得分:4)
如果您有多个锁A,B和C,如果您不保证您的代码尝试以相同的顺序获取所述锁,则可能会出现死锁。
final Lock A = new ReentrantLock();
final Lock B = new ReentrantLock();
final Lock C = new ReentrantLock();
A,B,C或C,B,A或A,C,B - 只要订单一致就无所谓。
当您有一个代码路径尝试:A,B,C时出现问题 另一个尝试C,B,A。
正如你可能猜到的那样,因为A和C都被保持,两者中的一个将得到B然后两者都会死锁。 (Aka你在资源锁定图中有一个循环)
正式地说,只有当以下所有条件都存在时,才会出现死锁:
最佳解决方案是确保订单一致或锁定在更高(单一)级别。另一个选择是使用一个锁定库,它会在尝试锁定时超时(或使用条件并编写自己的包装器来执行此操作)。但这种做法并不适合胆小的人。对此的一些实现将等待一段随机时间并再次尝试,但随着锁的数量增加,这可能是非常低效的。
<强>资源:强>
P.S。我实际上并没有阅读你的大部分代码,因为它的格式很差,并且不是一个最小的例子(即,我们的目的太冗长)。但是这个建议应该从理论的角度回答你的问题。
答案 1 :(得分:0)
这当然是可能的。您也可以在运行时检查!
第一步是获取线程转储。这有三种方法:
kill -3 <pid>
来获取堆栈,其中<pid>
是您的java进程ID。它会将相同的线程转储转储到stderr。该线程转储的底部还将包含它检测到的死锁的摘要。我不知道如何在Windows上执行此操作。jstack <pid>
,它会将线程转储打印到stdout(jstack
的标准输出,而不是原始的java进程'。)我编写了一个死锁并运行它的示例程序(参见my gist)。线程转储的相关部分是:
Found one Java-level deadlock:
=============================
"Thread-2":
waiting for ownable synchronizer 7f42b0f38, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
which is held by "Thread-1"
"Thread-1":
waiting for ownable synchronizer 7f42ba170, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
which is held by "Thread-2"
相关的帖子状态是:
"Thread-2" prio=5 tid=7fc01c911000 nid=0x113d18000 waiting on condition [113d17000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <7f30c3528> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:842)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1178)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:186)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
at Locky$Boomer.run(Locky.java:22)
at java.lang.Thread.run(Thread.java:680)
Locked ownable synchronizers:
- <7f30c3558> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
"Thread-1" prio=5 tid=7fc01d06c800 nid=0x113c15000 waiting on condition [113c14000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <7f30c3558> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:842)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1178)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:186)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
at Locky$Boomer.run(Locky.java:22)
at java.lang.Thread.run(Thread.java:680)
Locked ownable synchronizers:
- <7f30c3528> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
这对所有死锁无效。例如,由于等待外部资源而导致的死锁不会被捕获。但它会捕获基于Lock
的死锁,以及基于synchronized
的死锁。