深切怀念传智播客张孝祥老师,特将其代表作——Java并发库视频研读两遍,受益颇丰,记以后阅
04. 传统线程同步通信技术
面试题,子线程10次与主线程100次来回循环执行50次
下面是我刚看完面试题就暂停视频自己试着写的代码,还可以,结果完成要求了
在单次循环结束后让这个刚结束循环的线程休眠,保证另一个线程可以抢到执行权。
public class ThreadInterViewTest
{
/**
* 刚看到面试题没看答案之前试写
* 子线程循环10次,回主线程循环100次,
* 再到子线程循环10次,再回主线程循环100次
* 如此循环50次
*/
publicstatic void main(String[] args)
{
intnum = 0;
while(num++<50)//这种方法不好,new出来了50个线程
{
newThread(new Runnable()
{
@Override
public void run()
{
circle("子线程运行", 10);
}
}).start();
try
{
//加这句是保证上边的子线程先运行,刚开始没加,主线程就先开了
Thread.sleep(2000);
}catch (InterruptedException e)
{
e.printStackTrace();
}
circle("主线程", 100);
}
}
publicstatic synchronized void circle(String name, int count)
{
for(int i=1; i<=count; i++)
{
System.out.println(name+"::"+i);
}
try
{
Thread.sleep(5000);
}catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
张老师讲的方法:
1、将子线程和主线程中要同步的方法进行封装,加上同步关键字实现同步
2、两个线程间隔运行,添加一个标记变量进行比较以实现相互通信,加色的部分
wait notify notifyAll wait会抛出异常
class Business
{
private boolean bShouleSub = true;
publicsynchronized void sub()
{
if (bShouleSub)
此处使用while以增加程序健壮性,因为存在虚假唤醒,有时候并没有被notify就醒了。如果该方法没有同步的话,此处就更要使用while进行判断了,避免进程不同步问题
{
for (int i=1; i<11; i++)
SOP(sub+i);
bShouldSub= false;
this.notify();
}
else
this.wait();
}
publicsynchronized void main()
{
if (!bShouldSub)
{
for (int i=1; i<101; i++)
SOP(main+i);
bShouldSub= true;
this.notify();
}
else
this.wait();
}
}
经验:要用到共同数据(包括同步锁)或相同算法的多个方法要封装在一个类中
锁是上在代表要操作的资源类的内部方法中的,而不是上在线程代码中的。这样写出来的类就是天然同步的,只要使用的是同一个new出来的对象,那么这个对象就具有同步互斥特性
判断唤醒等待标记时使用while增加程序健壮性,防止伪唤醒
public class TraditionalThreadCommunication{
/**
* @param args
*/
publicstatic void main(String[] args) {
finalBusiness business = new Business();
newThread(
newRunnable() {
@Override
publicvoid run() {
for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();
for(int i=1;i<=50;i++){
business.main(i);
}
}
}
class Business {
private boolean bShouldSub = true;
public synchronized void sub(int i){
while(!bShouldSub){
try {
this.wait();
}catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
for(intj=1;j<=10;j++){
System.out.println("subthread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
this.notify();
}
public synchronized void main(int i){
while(bShouldSub){
try {
this.wait();
}catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
for(intj=1;j<=100;j++){
System.out.println("mainthread sequence of " + j + ",loop of " + i);
}
bShouldSub = true;
this.notify();
}
}
public class TraditionalThreadCommunication { /** * @param args */ public static void main(String[] args) { final Business business = new Business(); new Thread( new Runnable() { @Override public void run() { for(int i=1;i<=50;i++){ business.sub(i); } } } ).start(); for(int i=1;i<=50;i++){ business.main(i); } } } class Business { private boolean bShouldSub = true; public synchronized void sub(int i){ while(!bShouldSub){ try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int j=1;j<=10;j++){ System.out.println("sub thread sequence of " + j + ",loop of " + i); } bShouldSub = false; this.notify(); } public synchronized void main(int i){ while(bShouldSub){ try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int j=1;j<=100;j++){ System.out.println("main thread sequence of " + j + ",loop of " + i); } bShouldSub = true; this.notify(); } }