线程的同步
如果线程不同步,会发生两个线程抢占资源的问题;例如火车票出售时,只有最后一张票,但两个人一起买就会出现系统问题。所以为了避免资源抢占的问题,在使用线程的同步时应该考虑线程的安全
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();
}
}
}