我们讲到多线程,就离不开并发,讲到并发,就离不开安全性,这里我们先来实现一个简单功能能:买票系统
这是票的类,以及买票的方法:
public class DBTicket {
// 假设存放100张票
private static int num = 100;
public static void setNum(int num) {
DBTicket.num = num;
}
// 这是一个买票的方法
public static int getTicket(){
if(num < 1){
return 0;
}
return num --;
}
}
这是一个线程,模拟一个卖票窗口:
public class Thread1 implements Runnable {
@Override
public void run() {
// 打印哪个窗口(线程),买到哪张票
System.out.println(Thread.currentThread() +":"+DBTicket.getTicket());
}
}
模拟买票:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) throws Exception {
ExecutorService ex = Executors.newFixedThreadPool(10);
// 通过线程池, 模拟有3个窗口(线程),当然你可以建立不同的Thread 1 2 3
// 多执行几次
for(int i = 0;i<3;i++){
ex.execute(new Thread1());
ex.execute(new Thread1());
ex.execute(new Thread1());
}
ex.shutdown();
}
}
当你多执行几次的时候发现,会有重复的数字,不同的创窗口(线程),买到同样的票!你显然不不允许的。
OK,这是时候 很多人会说,加上关键字,synchronized ,就行了。是的,加上了 目前是安全的。
public static synchronized int getTicket(){
if(num < 1){
return 0;
}
return num --;
}
提示:这里加上 Thread.sleep(100) 模拟买票需要时间,效果更明显。
这里可以用java.util.concurrent.* 下面的 ReentrantLock 进行锁定;比如:
private void lookStatus(){
try{
lock.lock();
int num = getNum();
// 打印哪个窗口(线程),买到哪张票
System.out.println(Thread.currentThread() +":"+num);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
这里记得关闭 ,unlock 方法。不然会持有锁,不放的。具体请看API 或者源码,此类更更灵活。
发现内容比较多。还是整理一下,单独说线程的类吧