线程安全
- 概念:多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。
- 多个线程对全局变量、静态变量只有读操作的话,这个全局变量、静态变量一般来讲是线程安全的,如果有写操作而未考虑线程同步,就可能产生线程安全问题。
一个简单的例子,多个卖票窗口卖同一堆票:
public class Sell_ticket implements Runnable{
//有十张票
int ticket_num = 10;
@Override
public void run() {
while(true){
if(ticket_num>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"售出"+ticket_num);
ticket_num -= 1;
}
}
}
}
public class Main {
public static void main(String[] args) {
Sell_ticket st = new Sell_ticket();
Thread t0 = new Thread(st, "一号窗口");
Thread t1 = new Thread(st, "二号窗口");
Thread t2 = new Thread(st, "三号窗口");
t0.start();
t1.start();
t2.start();
}
}
一次运行结果如下:
三号窗口售出10
一号窗口售出10
二号窗口售出10
二号窗口售出7
一号窗口售出7
三号窗口售出7
一号窗口售出4
三号窗口售出4
二号窗口售出4
二号窗口售出1
三号窗口售出1
一号窗口售出-1
由上看出,几个线程间的票数不同步,这就是一种线程不安全。
线程同步
JAVA里的线程同步方法
同步锁Lock接口
某个线程在修改某个变量时,对其加上一个锁,这时其他线程就不能再对这个变量进行修改了,修改完成后再解锁。。
所在包:java.util.concurrent.locks.Lock
常用方法:
- public void lock() :加同步锁
- public void unlock() :释放同步锁
这里简单使用ReentrantLock(实现Lock接口的类)修改上述代码:
public class Sell_ticket implements Runnable{
//有十张票
int ticket_num = 10;
//创建同步锁
Lock lock = new ReentrantLock();
@Override
public void run() {
while(true){
//上锁
lock.lock();
if(ticket_num>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"售出"+ticket_num);
ticket_num -= 1;
}
//解锁
lock.unlock();
}
}
}
按照上述主函数运行之后的一次结果:
一号窗口售出10
二号窗口售出9
二号窗口售出8
三号窗口售出7
一号窗口售出6
一号窗口售出5
一号窗口售出4
二号窗口售出3
二号窗口售出2
二号窗口售出1
ok,问题解决。
关于Lock接口的使用方法还有很多,可以去看看API文档或者上网查(我分享的api文档)。以后用到更深入了回来填坑。
其他方法
留个坑…