一. 线程同步(synchronized)
(1)什么是线程同步:就是同一个线程操作同一个资源。如果线程不同步就是引发线程安全问题。
(2)如果同时有多个线程操作同一个资源,就会带来问题,如何避免问题的产生,可以使用互斥锁(synchronized),这是一个关键字。作用在同一份资源上时,给这个资源加上一把锁,你其他线程不许进来,等我处理结束后再说。
举个线程不安全的例子:
package thread;
public class Test2 {
public static class Bus extends Thread{
int tickets=50;
@Override
public void run() {
while(true){
String name=Thread.currentThread().getName();
if(tickets>=1){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name+"售出"+tickets--+"号座位");
}
}
}
}
public static void main(String[] args) {
Bus bus=new Bus();
Thread window1 =new Thread(bus);
window1.setName("window1");
window1.start();
Thread window2 =new Thread(bus);
window2.setName("window2");
window2.start();
Thread window3 =new Thread(bus);
window3.setName("window3");
window3.start();
}
}
从打印结果可以看出,不仅出现了重复座位,而且还出现了 0 号座位,存在极大的bug。出现bug的原因:多个线程参与同一个数据的操作,如上代码中,多个线程同时卖50张票,却没有给操作同一个资源加锁,就会出现这种bug。
(3)解决方法
- 同步代码块
修改 run(),添加 synchronized(Object obj) 关键字。这里一般传入 this ,this 即 Bus 类的对象。
public static class Bus extends Thread{
int tickets=50;
@Override
public void run() {
while(true){
String name=Thread.currentThread().getName();
synchronized (this) {
if(tickets>=1){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"售出"+tickets--+"号座位");
}
}
}
}
}
- 同步方法
public static class Bus extends Thread{
int tickets=50;
boolean flag=true;
@Override
public void run() {
while(flag){
sell();
}
}
public synchronized void sell(){
String name=Thread.currentThread().getName();
if(tickets>=1){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name+"售出"+tickets--+"号座位");
flag=true;
}else{
flag=false;
}
}
}