线程间共享代码和数据可以节省系统开销,提高程序运行效率,但同时也导致了数据的“访问冲突”问题,如何实现线程间的有机交互、并确保共享资源在某些关键时段只能被一个线程访问,即所谓的“线程同步”(Synchronization)就变得至关重要。
多个线程间共享的数据称为临界资源(Critical Resource),由于是线程调度器负责线程的调度,程序员无法精确控制多线程的交替顺序。因此,多线程对临界资源的访问有时会导致数据的不一致行。
package com.hbsi;
public class SaleTicket {
/**
* @param args
*/
public static void main(String[] args) {
TestSaleTicket ts=new TestSaleTicket();
Thread t1=new Thread(ts);
Thread t2=new Thread(ts);
t1.start();
t2.start();
}
}
class TestSaleTicket implements Runnable{
private int ticket=100;
Object obj=new Object();
public void run() {
while(true){
synchronized (obj) {
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-----"+ticket--);
}
}
}
}
}
B------------------
package com.hbsi;
public class SaleTicket1 {
/**
* @param args
*/
public static void main(String[] args) {
SaleTicket2 st=new SaleTicket2();
Thread t1=new Thread(st);
Thread t2=new Thread(st);
t1.start();
t2.start();
}
}
class SaleTicket2 implements Runnable{
private int ticket=100;
Object obj=new Object();
public void run(){
while(true){
show();
}
}
public synchronized void show(){
if(ticket>0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"..."+ticket--);
}
}
}
两个线程A、B用到同一个对象s(s为共享资源),且线程A在执行中要用到B运行后所创造的条件。在这种前提下A先开始运行,进入同步块后,对象s被锁定,接着线程A因等待B运行结束而进入阻塞状态,于是B开始运行,但因无法访问对象s,线程B也进入阻塞状态,等待s被线程A解锁。最终的结果:两个线程互相等待,都无法运行。
package com.hbsi;
public class DeadLock {
/**
* @param args
*/
public static void main(String[] args) {
Demo6 d1=new Demo6(true);
Demo6 d2=new Demo6(false);
Thread t1=new Thread(d1);
Thread t2=new Thread(d2);
t1.start();
t2.start();
}
}
class MyLock{
static MyLock lock1=new MyLock();
static MyLock lock2=new MyLock();
}
class Demo6 implements Runnable{
//String str1=new String("aaa");
//String str2=new String("bbb");
private boolean flag;
public Demo6(boolean flag){
this.flag=flag;
}
@Override
public void run() {
if(flag){
synchronized(MyLock.lock1){
System.out.println(Thread.currentThread().getName()+"...if...str1");
synchronized(MyLock.lock2){
System.out.println(Thread.currentThread().getName()+"...if...str2");
}
}
}else{
synchronized(MyLock.lock2){
System.out.println(Thread.currentThread().getName()+"...else...str2");
synchronized(MyLock.lock1){
System.out.println(Thread.currentThread().getName()+"...else...str1");
}
}
}
}
}
小总结:Synchronization关键字是一个修饰符,可以修饰方法或代码块。其作用就是:对于同一个对象(不是一个类的不同对象),当多个线程都同时调用该方法或代码块时,必须依次执行,也就是说,如果两个或两个以上的线程同时执行该段代码,如果一个线程已经开始执行该段代码,则另一个线程必须等待这个线程执行完这段代码才能开始执行。