java多线程艺术:线程同步
问题引出
/*
* 实现买票案例
* */
public class RunnableImpl implements Runnable{
//定义一个多线程共享的票源
private int ticket=100;
// 设置线程任务:买票
@Override
public void run() {
/**
// 单线程模式 卖票方式
//先判断票是否存在
if(ticket>10){
//票存在,买票ticket
System.out.println(Thread.currentThread().getName()+"正在卖第----->"+ticket+"张票");
ticket--;
}
*/
// 多线程卖票方式
//使用死循环,让卖票操作重复执行
while (true){
//先判断票是否存在
if(ticket>10){
// 提高安全问题出现的概率 让程序睡眠
// try...catch... 这个代码不是必须的 目的让大家看到有重复现象 说明这个卖票系统存在不合理
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//票存在,买票ticket
System.out.println(Thread.currentThread().getName()+"正在卖第----->"+ticket+"张票");
ticket--;
}
}
}
}
/*
模拟卖票案例
创建3个线程(相当于 三个卖票窗口) 对共享的票进行出售
*/
public class Driver {
public static void main(String[] args) {
// 创建Runnable 接口的实现类对象
RunnableImpl run=new RunnableImpl();
// 创建Thread类对象 构造方法中传递Runnable 接口的实现类对象
Thread t1=new Thread(run);
Thread t2=new Thread(run);
Thread t3=new Thread(run);
// 调用start 方法开启多线程
t1.start();
t2.start();
t3.start();
}
}
解决不同步的手段
- 同步代码块
- 同步方法
- 锁机制
同步代码块
/*
* 卖票案例出现了线程安全问题
* 卖出了不存在的票和重复的票
*
*
* 解决线程安全问题的一种方案: 使用同步代码块
*
* 格式:
* synchronized(锁对象){
* 可能会出现线程安全问题的代码(访问了 共享数据的代码)
* }
*
* 注意:
* 1. 通过代码块中的锁对象,可以使用任意的对象
* 2. 但是必须保证多个线程使用的锁对象是同一个
* 3.锁对象作用: 把同步代码块锁住,只让一个线程 在同步代码块中执行
*
*
* */
public class RunnableImpl implements Runnable {
//定义一个多线程共享的票源
private int ticket = 100;
//创建锁对象 留一个问题思考一下 为什么 锁对象不写在 run() 方法里
Object obj = new Object();
// 设置线程任务:买票
@Override
public void run() {
/**
// 单线程模式 卖票方式
//先判断票是否存在
if(ticket>10){
//票存在,买票ticket
System.out.println(Thread.currentThread().getName()+"正在卖第----->"+ticket+"张票");
ticket--;
}
*/
// 多线程卖票方式
//使用死循环,让卖票操作重复执行
while (true) {
// 同步代码块
synchronized (obj) {
//先判断票是否存在
if (ticket > 0) {
// 提高安全问题出现的概率 让程序睡眠
// try...catch... 这个代码不是必须的 目的让大家看到有重复现象 说明这个卖票系统存在不合理
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//票存在,买票ticket
System.out.println(Thread.currentThread().getName() + "正在卖第----->" + ticket + "张票");
ticket--;
}
}
}
}
}
同步方法
/*
* 卖票案例出现了线程安全问题
* 卖出了不存在的票和重复的票
*
*
* 解决线程安全问题的一种方案: 使用同步方法
*
* 使用步骤:
* 1. 把访问了共享数据的代码抽取出来,放到一个方法中
* 2. 在方法上添加synchronized修饰符
*
* 语法格式: 定义方法的格式
* 修饰符 synchronized 返回值类型 方法名(参数列表){
*
* 可能会出现线程安全问题的代码(访问了 共享数据的代码)
* }
* */
public class RunnableImpl implements Runnable {
//定义一个多线程共享的票源
private int ticket = 100;
//创建锁对象 留一个问题思考一下 为什么 锁对象不写在 run() 方法里
Object obj = new Object();
// 设置线程任务:买票
@Override
public void run() {
System.out.println("this:\t"+this);
// 多线程卖票方式
//使用死循环,让卖票操作重复执行
while (true) {
payTicket();
}
}
/**
* 定义一个 同步方法
*
*
*同步方法也会把方法内部的代码锁住
*
* 只让一个线程执行
*
* 同步方法的锁对象是谁?
* 就是实现类对象 new RunnableImpl()
* 也就是 this
*/
public synchronized void payTicket() {
//先判断票是否存在
if (ticket > 0) {
// 提高安全问题出现的概率 让程序睡眠
// try...catch... 这个代码不是必须的 目的让大家看到有重复现象 说明这个卖票系统存在不合理
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//票存在,买票ticket
System.out.println(Thread.currentThread().getName() + "正在卖第----->" + ticket + "张票");
ticket--;
}
}
/**
* 上面同步方法 还可以等价写法 如下
*
*
* public void payTicket() {
*
* synchronized (this){
*
* //先判断票是否存在
* if (ticket > 0) {
* // 提高安全问题出现的概率 让程序睡眠
* // try...catch... 这个代码不是必须的 目的让大家看到有重复现象 说明这个卖票系统存在不合理
*
* try {
* Thread.sleep(10);
* } catch (InterruptedException e) {
* e.printStackTrace();
* }
* //票存在,买票ticket
* System.out.println(Thread.currentThread().getName() + "正在卖第----->" + ticket + "张票");
* ticket--;
* }
*
* }
*
*
*
* }
*
*
*
*/
}
静态同步方法
锁对象是谁?
不能是this
this 是创建对象之后产生的,静态方法优先对象
静态方法的锁对象是本类的class属性--->class 文件对象(反射)
Lock锁机制
posted on 2019-05-26 11:47 Indian_Mysore 阅读(202) 评论(0) 编辑 收藏 举报