例题:线程A输出1-52,线程B输出A-Z,最后的输出结果是:12A34B56C…。
首先要想依次输出,需要实现两个线程之间的通信,线程之间的通讯可以通过共享对象来实现
思路:两个线程A,B都实现Runnable接口,在C线程的main方法中,定义一个Object变量,并且将这个Object变量传入到A,B的构造方法中,当创建A,B两个线程的时候,通过有参的构造方法创建,在for循环中添加同步代码块,在A线程中,执行两次循环,让该线程休眠并唤醒别的线程(这里写代码时候,是先唤醒notifyAll(),然后wait()),B线程中是执行一次循环,就让线程休眠并唤醒其他线程。
不过这个思路有一个不足,就是不一定会先输出数字,因为A,B不知道谁会先抢到CPU。此时,可以通过创建一个具有属性的对象,利用对象中的属性来进行判断,比如创建了一个Foo对象,Foo有一个属性“x=1”,当x=1的时候,才进行执行A线程。如果B先抢到了CPU,此时判断x!=1,那么就让B线程修眠。
以Object为共享对象的代码实现
class A implements Runnable{
private Object obj;
public A(Object obj){
this.obj = obj;
}
@Override
public void run() {
synchronized (obj){
for (int i=1;i<=52;i++){
System.out.println(i);
if(i%2==0){
obj.notifyAll();
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
class B implements Runnable{
private Object obj;
public B(Object obj){
this.obj = obj;
}
@Override
public void run() {
synchronized (obj){
for (int i='A';i<='Z';i++){
System.out.println((char)i);
obj.notifyAll();
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class C {
public static void main(String[] args) {
Object obj = new Object();
A a = new A(obj);
B b = new B(obj);
Thread t1 = new Thread(a);
Thread t2 = new Thread(b);
t1.start();
t2.start();
}
}
以Foo为共享对象的代码实现
class Foo{
public int x = 1;
}
class A implements Runnable{
private Foo foo;
public A(Foo foo){
this.foo = foo;
}
@Override
public void run() {
synchronized (foo){
/*
这里要想输出Z,则i<=53,
因为当输出完52的时候,i++则会变为53,
此时for循环就结束了,就不会执行唤醒线程,所以没有办法输出Z,
但是这样的话,线程总会有线程是阻塞状态,
所以另一种办法就是通过判断,
即当执行到52或者Z的时候,不再用wait()
本代码中使用的是第二种办法
*/
for (int i=1;i<=52;i++){
while (foo.x!=1){
foo.notifyAll();
try {
foo.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(i);
if(i%2==0){
foo.x=2;
}
if(i==52){
foo.notifyAll();
}
}
}
}
}
class B implements Runnable{
private Foo foo;
public B(Foo foo){
this.foo = foo;
}
@Override
public void run() {
synchronized (foo){
for (int i='A';i<='Z';i++){
while (foo.x!=2){
foo.notifyAll();
try {
foo.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println((char)i);
foo.x=1;
if(i=='Z'){
foo.notifyAll();
}
}
}
}
}
public class C {
public static void main(String[] args) {
Foo foo = new Foo();
A a = new A(foo);
B b = new B(foo);
Thread t1 = new Thread(a);
Thread t2 = new Thread(b);
t2.start();
t1.start();
}
}
其实在视频课上并没有发现按照老师的代码输出不了Z,并不是说老师教的不好或者怎么样,老师也是偶然想到,才引申出优化的那一个实现。
是自己觉得,学习了java这么久,第一次觉得,对待编程要认真,严谨,要去思考解决思路,最主要是自己动脑思考,并且要努力实践。这样才会发现其中的乐趣。
还有要努力钻研。