package com.tianmushanlu.thread;
/**
* 创建步骤:
* 1. 自定义一个类继承Thread类。
* 2. 重写Thread类的run方法,把自定义线程的任务代码写在run方法上。
* 3. 创建Thread的子类对象,并且调用start方法启动一个线程。
*
* 出现线程安全问题的根本原因:
* 1. 存在两个或者两个以上 的线程对象,而且线程之间共享着一个资源。
* 2. 有多个语句操作了共享资源。(使用同步代码块,使多个语句操作同步执行)
*
* 同步代码块要注意事项:
* 1. 任意的一个对象都可以做为锁对象
* 2. 在同步代码块中调用了sleep方法并不是释放锁对象的。
* 3. 只有真正存在线程安全问题的时候才使用同步代码块,否则会降低效率的。
* 4. 多线程操作的锁 对象必须 是唯一共享 的。否则无效。
*
*
*
*/
class TicketWindow extends Thread {
/**
* 票数
* 非静态的成员变量,非静态的成员变量数据是在每个对象中都会维护一份数据的。
*
* num是非静态的,
* 非静态的成员变量数据是在每个对象中都会维护一份数据的,三个线程对象就会有三份。(见图1所示)
*/
static Integer num = 50;
public TicketWindow(String name) {
super(name);
}
@Override
public void run() {
while(true) {
/**
* 使用同步代码块,使多个语句操作同步执行
* 原则上任意的对象都可以作为锁对象,凡是对象内部都维护了一个状态的
* java中同步机制就是使用了对象的状态作为了锁的标识
* state = 0 ----->开
* state = 1 ----->关
* 因而锁对象必须是一个共享对象
* 此对象必须用static修饰,如:
* static Object o = new Object();
* synchronized (o){
* 需要被同步的代码..................
* }
*
*如下方式是最简单的锁对象,
* 因为双引号引起来的字符串一旦存在了字符串常量词中就不会再创建了,
* 因而所有的线程都将共同使用字符串常量词中的那个锁对象
* synchronized ("锁对象") {
* 需要被同步的代码..................
* }
*
*/
synchronized ("锁对象") {
if(num > 0) {
System.out.println(Thread.currentThread().getName()+"售出了第"+num+"票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
}else{
System.out.println("票以售罄...........");
break;
}
}
}
}
}
public class ThreadDemo{
public static void main(String[] args) {
/**
* 创建3个窗口进行售票
*/
TicketWindow thread1 = new TicketWindow("售票窗口1");
TicketWindow thread2 = new TicketWindow("售票窗口2");
TicketWindow thread3 = new TicketWindow("售票窗口3");
/**
* 开启线程售票
*/
thread1.start();
thread2.start();
thread3.start();
}
}