线程的执行顺序和同步

import java.util.concurrent.atomic.AtomicBoolean;

/*
线程的加入(join)

如果有一个A执行绪正在运行,您希望插入一个B线程,并要求B线程先执行完毕,然后再继续A线程的流程,您可以使用 join()方法来完成这个需求,这就好比您手头上正有一个工作在进行,老板插入一个工作要求您先作好,然后再进行您原先正进行的工作。

当线程使用join()加入至另一个线程时,另一个线程会等待这个被加入的线程工作完毕,然后再继续它的动作,使用下面这个简单的例子就可以说明:
*/


public class ThreadA {

public static void main(String[] args)
{
final AtomicBoolean complete = new AtomicBoolean(false);
System.out.println("Thread A 执行1");
Thread threadB=new Thread(new Runnable(){

public void run() {
// TODO Auto-generated method stub
System.out.println("Thread B 开始");
for(int i=0;i<5;i++)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Thread B 执行");
}

complete.set(true);
synchronized (complete) {
System.out.println("唤醒");
complete.notify();//唤醒的线程与当前线程并行运行
}
System.out.println("Thread B 即将结束");
}

});
threadB.start();
/*try {
threadB.join();//此处插入threadB,主线程一直等待threadB结束
//threadB.join(2000);//主线程等待threadB 2s
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/



synchronized (complete) {
if (!complete.get()) {
try {
System.out.println("等待1");
Thread.sleep(5000);// sleep之后threadB获得资源
//complete.wait();//释放了同步锁,要唤醒之后才执行

System.out.println("等待2");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
System.out.println("Thread A 执行2");
}


}
本程序的执行结果:
Thread A 执行1
等待1
Thread B 开始
Thread B 执行
Thread B 执行
Thread B 执行
Thread B 执行
Thread B 执行(此时主线程还没有释放同步锁,sleep不会释放同步锁,wait会释放同步锁)
等待2
Thread A 执行2
唤醒(等到同步块执行后,释放了同步锁,此时执行此语句)
Thread B 即将结束

/*
程序启动后主线程就开始,在主线程中您新建threadB,并在启动threadB后,将之加入(join)主线程的流程之中,threadB必须先执行完毕,主线程才会再继续它原本的流程,执行结果如下:

Thread A 执行
Thread B 开始
Thread B 执行
Thread B 执行
Thread B 执行
Thread B 执行
Thread B 执行
Thread B 即将结束
Thread A 执行



如果程序中没有将threadB使用join()将之加入主线程的流程中,则最后一行显示"Thread A 执行"的陈述会先执行完毕(因为threadB使用了sleep(),这让主线程有机会取得时间来执行)。如注释掉threadB.join();,则运行结果为:

Thread A 执行
Thread A 执行
Thread B 开始
Thread B 执行
Thread B 执行
Thread B 执行
Thread B 执行
Thread B 执行
Thread B 即将结束

有时候这个加入的线程有可能处理太久,您不想无止境的等待这个线程的工作完毕,则您可以在join()上指定时间,例如 join(10000),表示至多等待10000毫秒,也就是10秒,如果加入的线程还没执行完毕就不管它,当前的线程可以继续执行工作。如把threadB.join()改为threadB.join(3000);运行结果为:

Thread A 执行
Thread B 开始
Thread B 执行
Thread B 执行
Thread B 执行
Thread A 执行
Thread B 执行
Thread B 执行
Thread B 即将结束

虽然3秒后B线程还没执行完就执行主线程,但B线程并没有消亡,这可以从结果中可以看出来.

*/


特别说明(两个同步块):
synchronized (complete) {
System.out.println("唤醒");
complete.notify();//唤醒的线程与当前线程并行运行
}

synchronized (complete) {
if (!complete.get()) {
try {
System.out.println("等待1");
Thread.sleep(5000);// sleep之后threadB获得资源
//complete.wait();//在此处会出现阻塞,这时释放了同步锁,要唤醒之后后面才执行

System.out.println("等待2");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

[color=red]
注意问题[/color] synchronized关键词一般用于虚拟锁,锁住的不是方法或代码,而是调用这个方法的对象。例如,对于一个构造函数Test(int n),由于变量n的不同,可以[color=red]构造出不同的Test对象a和b,如果a、b同时访问同步区域,结果只会使synchronized形同虚设![/color] a和b如果要同时访问同步方法,只有该同步方法为[color=red]static[/color]时才能达到同步的目的,否则,a调用a的方法,b调用b的方法,即使方法声明为同步的,但在不同对象域中它们根本达不到同步的目的。

1.不同的对象对一般的同步方法不起作用,同步方法一般为static
2.多线程中访问同一个实例的同步方法时会进行同步,同步变量一般是final和 static约束的
3.对线程的run()进行同步没有意义
4.sleep不会释放同步锁,wait会释放同步锁,要通过notify来唤醒
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值