当用多线程处理一个卖票问题时 设置3个线程窗口 一起进行卖票
public class ThreadTestSync {
public static void main(String[] args) {
SellTicket sellTicket = new SellTicket();
Thread sell01 = new Thread(sellTicket);// 窗口1
sell01.setName("窗口1");
Thread sell02 = new Thread(sellTicket);// 窗口2
sell02.setName("窗口2");
Thread sell03 = new Thread(sellTicket);// 窗口3
sell03.setName("窗口3");
sell01.start();
sell02.start();
sell03.start();
}
}
class SellTicket implements Runnable {
private int ticketNum = 100; //票总数
private boolean loop = true;
private int count;
public void sell() {
while (loop) {
if (ticketNum <= 0) {
System.out.println("票已经售罄");
break;
}
System.out.println(Thread.currentThread().getName() + "售出第" + (++count)
+ "张票 还剩下" + (--ticketNum) + "张票");
try {
Thread.sleep(100);//休眠100毫秒
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void run() {
sell();
}
}
结果中出现了票已售罄 还在出售的情况 证明当判断到达临界条件时 同时有多个线程进入 要求在判断与售卖过程中只允许一个线程进入 进行线程同步 即当有一个线程对内存进行操作时 其他线程都不可以对这个内存地址进行操作 直到该线程完成操作
同步方法-Synchronized
synchronized(对象) { //得到对象锁才可进入同步代码
//同步代码
}
synchronized也可声明方法 表示该方法为同步方法
每一个对象都对应一个互斥锁 这个用于保证 在任何同一时刻只能有一个线程访问该对象 关键字synchronized用来与对象的互斥锁联系
因为同步代码 要求在同一时刻只能有一个线程访问 导致程序的执行效率降低
所以需要被同步的代码 应尽可能的少 因此需线程同步时 应使用同步代码块的方式
class SellTicket implements Runnable {
private int ticketNum = 100; //票总数
private boolean loop = true;
private int count;
public void sell() {
while (loop) {
synchronized (this) { //需要被同步的代码
if (ticketNum <= 0) {
System.out.println("票已经售罄");
break;
}
System.out.println(Thread.currentThread().getName() + "售出第" + (++count)
+ "张票 还剩下" + (--ticketNum) + "张票");
}
try {
Thread.sleep(100);//休眠100毫秒
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void run() {
sell();
}
}
继承Thread创建线程 实现同步
class SellTicket02 extends Thread{
private static int ticketNum = 100; //票总数
private static boolean loop = true;
private static int count;
public void sell() {
while (loop) {
synchronized (this) { //需要被同步的代码
if (ticketNum <= 0) {
System.out.println("票已经售罄");
break;
}
System.out.println(Thread.currentThread().getName() + "售出第" + (++count)
+ "张票 还剩下" + (--ticketNum) + "张票");
}
try {
Thread.sleep(100);//休眠100毫秒
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void run() {
sell();
}
}
在非静态同步方法中的锁可以是this 也可是其他的 同一个对象
而静态的同步方法的 锁为当前类本身
当继承 Thread类 创建线程 使用上面实现Runnable接口 线程同步的方式后发现并没有限制住线程进入 其原因是继承Thread类创建线程 在调用时 new 三个不同的对象 去执行线程 每个对象都对应了一把互斥锁 进入同步代码时每个对象都可以拿到自己锁进入同步代码 需要这三个对象共用一把互斥锁才可实现线程同步 可进行以下修改
public static void sell() {//将该方法设置为静态方法
...
synchronized (SellTicket02.class) {//静态的同步方法的 锁为当前类本身
....
}
....
}