来看一个面试题目
在子线程中执行一段代码10次,然后在主线程中执行代码50次,然后再在子线程中执行代码10次,然后是主线程....这样循环50次,应该如何实现
这个题目考验的是线程的互斥和通信,互斥就是加一个锁,通信就是设置一个共享的值,我以为很简单就用下面的代码实现
<pre name="code" class="java">package day20150802;
import org.junit.Test;
public class CopyOfMainAndSubThreadTest2 {
private final static Object Monitor = new Object();
private static boolean first = false;
private static boolean control = true;
@Test
public void main() {
final Run run = new Run();
new Thread(new Runnable() {
public void run() {
for(int sub = 0;sub<50;sub++){
run.sub(sub);
}
}
} ).start();
for(int sub = 0;sub<50;sub++){
run.main(sub);
}
}
}
class Run{
private final Object Monitor = new Object();
private boolean control =true;
public void main(int j){
synchronized(this.Monitor){
while(!control){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int i = 0;i<50;i++)
System.out.println("main "+(j+1)+"--"+(i+1));
control=false;
}
notify();
}
public void sub(int sub) {
synchronized(this.Monitor){
while(control){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println(e);
e.printStackTrace();
}
}
for(int i = 0;i<10;i++){
System.out.println("sub "+(sub+1)+"--"+(i+1));
}
control=true;
}
this.notify();
}
}
执行结果:
[Console output redirected to file:C:\Myeclipse\MyEclipse 10\OutPutTest.JavaTestOutTxt]
main 1--1
main 1--2
main 1--3
main 1--4
main 1--5
main 1--6
.....
main 1--49
main 1--50
sub 1--1
sub 1--2
sub 1--3
sub 1--4
sub 1--5
sub 1--6
sub 1--7
sub 1--8
sub 1--9
sub 1--10
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)at day20150802.Run.sub(CopyOfMainAndSubThreadTest2.java:61)
at day20150802.CopyOfMainAndSubThreadTest2$1.run(CopyOfMainAndSubThreadTest2.java:15)
at java.lang.Thread.run(Thread.java:619)
而把 synchronized 锁加到 方法上面就可以运行了,代码如下
<pre name="code" class="java">package day20150802;
import org.junit.Test;
public class CopyOfMainAndSubThreadTest2 {
private final static Object Monitor = new Object();
private static boolean first = false;
private static boolean control = true;
@Test
public void main() {
final Run run = new Run();
new Thread(new Runnable() {
public void run() {
for(int sub = 0;sub<50;sub++){
run.sub(sub);
}
}
} ).start();
for(int sub = 0;sub<50;sub++){
run.main(sub);
}
}
}
class Run{
private final Object Monitor = new Object();
private boolean control =true;
public synchronized void main(int j){
while(!control){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int i = 0;i<50;i++)
System.out.println("main "+(j+1)+"--"+(i+1));
control=false;
this.notifyAll();
}
public synchronized void sub(int sub) {
while(control){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println(e);
e.printStackTrace();
}
}
for(int i = 0;i<10;i++){
System.out.println("sub "+(sub+1)+"--"+(i+1));
}
control=true;
this.notifyAll();
}
}
这是为什么??
这个异常是说,若不拥有对象的锁标记,而试图用wait/notify协调共享对象资源,应用程序将抛出IllegalMonitorStateException。
我看查询完资料后发现,synchronized是获取对象内部的锁,而我使用同步代码块的时候,获取的是Monitor的内部锁,而不是这个类的内部锁,所以,this.notify();改为this.Monitor.notify()就可以了
package day20150802;
import org.junit.Test;
public class CopyOfMainAndSubThreadTest2 {
private final static Object Monitor = new Object();
private static boolean first = false;
private static boolean control = true;
@Test
public void main() {
final Run run = new Run();
new Thread(new Runnable() {
public void run() {
for(int sub = 0;sub<50;sub++){
run.sub(sub);
}
}
} ).start();
for(int sub = 0;sub<50;sub++){
run.main(sub);
}
}
}
class Run{
private final Object Monitor = new Object();
private boolean control =true;
public void main(int j){
synchronized(this.Monitor){
while(!control){
try {
this.Monitor.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int i = 0;i<50;i++)
System.out.println("main "+(j+1)+"--"+(i+1));
control=false;
this.Monitor.notifyAll();
}
}
public void sub(int sub) {
synchronized(this.Monitor){
while(control){
try {
this.Monitor.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println(e);
e.printStackTrace();
}
}
for(int i = 0;i<10;i++){
System.out.println("sub "+(sub+1)+"--"+(i+1));
}
control=true;
this.Monitor.notifyAll();
}
}
}