基本介绍
线程同步机制:在多线程编程下,一些敏感数据不允许被多个现在在同一时刻访问,此时就使用同步访问机制,保证数据在任何同一时刻最多只有一个进程访问,以保证数据的完整性。(即:当有一个线程在对内存操作时,其他的线程都不允许对这个内存地址进行操作,指代该线程完成操作,其他的线程才能对内存地址进行操作)
细节讨论
- 关键字synchronized来与对象的互斥锁联系。当某个对象来用synchronized修饰时,表明该对象在任何一时刻只能由一个线程访问
- 同步的局限性:导致程序的执行效率低,因为同一时刻只能执行一个线程
- sychronized可以修饰方法也可以修饰代码块,分别称为同步方法和同步代码块。一般情况下建议使用同步代码块,因为这样的效率要高一些
- 同步方法(非静态)的锁对象可以是this,也可以是其他对象(要求是同一个对象)
- 同步方法(静态的)的锁对象是当前类本身
使用synchronized来处理售票时线程同步的问题:
代码:
public class Threads {
public static void main(String[] args) {
//会出现票超卖现象,原因:当我们还有1张票时,可能一下子来了2个线程,此时判断是否<=0时都不小于,所以继续往下执行卖票,导致票超卖现象
Windows windows = new Windows();
//同一个对象
Thread thread1 = new Thread(windows);
thread1.setName("窗口1");//设置线程的名字
Thread thread2 = new Thread(windows);
thread2.setName("窗口1");
Thread thread3 = new Thread(windows);
thread3.setName("窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}
class Windows implements Runnable {
private static int tickets = 100;//共享100张票
private /*static*/ Boolean loop = true;//控制run方法变量
public /*static*/ void sell() {//同步方法
// Object object = new Object();
synchronized (/*当方法为静态时锁对象是当前类本身为:Windows.class*/this/*当为非静态方法时也可以为object,因为object是这个类的对象,是同一个对象*/) {
if (tickets <= 0) {
System.out.println("没票了");
loop = false;
return;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩" + (--tickets));
}
}
@Override
public void run() {
while (loop) {
sell();
// synchronized (this) {//同步代码块
// if (tickets <= 0) {
// System.out.println("没票了");
// loop = false;
// return;
// }
//
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// System.out.println("窗口" + Thread.currentThread().getName() + "卖了一张票,还剩" + (--tickets));
// }
}
}
}
注意:一定要是同一个对象,如上述的windows。如果是不同的对象的话,相当于是不同的对象锁了,也就是不只一把锁,各用各的,当然就起不到线程同步了。比如:你要进厕所去方便,现在这个房间的门就相当于是对象锁,只能等里面的人出来后你在进入。若此时是不同的对象的话,就相当于有不同的门,也就是说现在这个厕所有不同的门可以进入了,那样就起不到防护机制了。