Java线程的同步--线程安全的原因及解决方法
线程的同步
如果线程不同步,会发生两个线程抢占资源的问题;例如火车票出售时,只有最后一张票,但两个人一起买就会出现系统问题。所以为了避免资源抢占的问题,在使用线程的同步时应该考虑线程的安全
1.不安全的线程: 同一进程下不同的线程是共享系统资源的,资源好比一个独木桥,如果两个线程,同时过独木桥的话就会发生不安全的情况(资源的抢用会造成:脏数据,死锁等问题)
2.安全的线程: 过独木桥时,一个先给出指令先过桥,过完后再次发出指令,已经完成过桥 要保证线程的安全:需要给线程加锁: 加锁—’过桥‘—解锁
加锁:synchronized关键字 同步方法:synchronized void method(){ } 同步代码块 synchronized(Object){
} Object:任意对象,仅作为加锁的标志
首先举一个不安全的线程同步例子:
//模拟售票系统
public class 同步 implements Runnable{
int num = 10;//票池的总数
public static void main(String[] args) {
同步 d =new 同步();
Thread t1= new Thread(d,"线程1");//售票机1
Thread t2= new Thread(d,"线程2");//售票机2
Thread t3= new Thread(d,"线程3");//售票机3
Thread t4= new Thread(d,"线程4");//售票机4
t1.start();
t2.start();
t3.start();
t4.start();
}
public void run() {
while(true) {
if(num>0)
try {
Thread.sleep(100);//休眠100毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("票数:"+num);
num--;
if(num<0) {
break;
}
}
}
}
结果如下: 票数:10 票数:7 票数:8 票数:9 票数:6 票数:3 票数:4 票数:5 票数:2 票数:1 票数:0 票数:-1 票数:-2 票数:-3
采用同步代码块的方法使线程安全:
//模拟售票系统
public class 同步 implements Runnable{
int num = 10;//票池的总数
public static void main(String[] args) {
同步 d =new 同步();
Thread t1= new Thread(d,"线程1");//售票机1
Thread t2= new Thread(d,"线程2");//售票机2
Thread t3= new Thread(d,"线程3");//售票机3
Thread t4= new Thread(d,"线程4");//售票机4
t1.start();
t2.start();
t3.start();
t4.start();
}
public void run() {
while(true) {
synchronized (this) {
//同步代码块,所以线程同步此代码块
if(num>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println("票数:"+num);
num--;
if(num<0) {
System.out.println("已售空");
break;
}
}
}
}
}
}
采用同步方法的解决方法
//模拟售票系统
public class 同步 implements Runnable{
int num = 10;//票池的总数
public static void main(String[] args) {
同步 d =new 同步();
Thread t1= new Thread(d,"线程1");//售票机1
Thread t2= new Thread(d,"线程2");//售票机2
Thread t3= new Thread(d,"线程3");//售票机3
Thread t4= new Thread(d,"线程4");//售票机4
t1.start();
t2.start();
t3.start();
t4.start();
}
private synchronized void sell() {
//线程同步的方法
if(num>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println("票数:"+num);
num--;
if(num<0) {
System.out.println("已售空");
}
}
}
public void run() {
while(true) {
sell();
}
}
}
