1.线程安全问题的概述

2.线程安全问题的代码实现和分析
package com.study_06.ThreadSafe;public class RunnableImpl implements Runnable {// 定义一个多个线程共享的票源private int ticket = 100;// 卖票@Overridepublic void run() {// 使用死循环 让买票重复执行while (true) {// 先判断票是否存在if (ticket > 0) {// 提高安全问题出现的概率,让程序睡眠try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//票存在 ticket---System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");ticket--;}}}}
package com.study_06.ThreadSafe;public class Demo01Ticket {public static void main(String[] args) {// 创建Runnable接口实现对象RunnableImpl run = new RunnableImpl();// 创建Thread类对象,构造方法中传递Runnable接口实现类对象Thread t0 = new Thread(run);Thread t1 = new Thread(run);Thread t2 = new Thread(run);// 调用start方法开启多线程t0.start();t1.start();t2.start();}}

3.线程同步
- 同步代码块
- 同步方法
- 锁机制
4.同步代码块
同步代码块:
synchronized关键字可以用与方法中的某个区块中,表示只对这个区域的资源实行互斥访问格式:
synchronized(同步锁){需要同步操作的代码}
同步锁
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁
- 锁对象 可以是任意类型
- 多个线程对象 要使用同一把锁
注意: 在任何时候吗,最多允许一个线程拥有同步锁,谁拿到锁谁就进入代码块中,其它的线程只能在外面等着(BLOCKED)
代码改进:
package com.study_07.Synchronized;/*1.通过代码块中的锁对象,可以使用任意的对象2.但是必须保证多个线程使用的锁对象是同一个3.锁对象作用:把同步代码块锁住,只让一个线程在同步代码块中执行*/public class RunnableImpl implements Runnable {// 定义一个多个线程共享的票源private int ticket = 100;// 创建一个锁对象Object obj = new Object();// 卖票@Overridepublic void run() {// 使用死循环 让买票重复执行while (true) {// 创建同步代码块synchronized (obj) {// 先判断票是否存在if (ticket > 0) {// 提高安全问题出现的概率,让程序睡眠try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//票存在 ticket---System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");ticket--;}}}}}
5.同步技术的原理

6.同步方法
同步方法:使用
synchronized修饰的方法,就叫做同步方法,保证A线程 执行该方法的时候,其它线程只能在方法外等着格式:
public synchronized void method(){可能会产生线程安全问题的代码}
同步锁是谁? 对于非static方法,同步锁就是this 对于static方法,我们使用当前方法所在类的字节码对象(类名.class)
package com.study_08.Synchronized;public class RunnableImpl implements Runnable {// 定义一个多个线程共享的票源private int ticket = 100;// 卖票@Overridepublic void run() {// 使用死循环 让买票重复执行System.out.println("this:"+this);while (true) {payTicket();}}/*定义一个同步方法同步方法也会把方法内部的代码锁住只让一个线程执行同步方法的对象是谁?就是实现类对象*/public synchronized void payTicket() {// 先判断票是否存在if (ticket > 0) {// 提高安全问题出现的概率,让程序睡眠try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//票存在 ticket---System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");ticket--;}}}
7.静态同步方法
package com.study_08.Synchronized;public class RunnableImpl implements Runnable {// 定义一个多个线程共享的票源private static int ticket = 100;// 卖票@Overridepublic void run() {// 使用死循环 让买票重复执行System.out.println("this:"+this);while (true) {payTicket();}}/*静态同步方法锁对象是谁?不能是thisthis是创建对象之后产生的,静态方法优先于对象静态的锁对象是本类的class属性-->class文件对象(反射)*/public static /*synchronized*/ void payTicket() {// 先判断票是否存在synchronized (RunnableImpl.class) {if (ticket > 0) {// 提高安全问题出现的概率,让程序睡眠try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//票存在 ticket---System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");ticket--;}}}}
8.Lock锁
package com.study_09.Lock;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*使用Lock锁Lock实现提供了比使用synchronized方法和语句课获得的跟广泛的锁定操作Lock接口中的方法:void lock() 获取锁void unlock() 释放锁*/public class RunnableImpl implements Runnable {// 定义一个多个线程共享的票源private int ticket = 100;// 1. 在成员位置创建一个ReentrantLock对象Lock l = new ReentrantLock();// 卖票@Overridepublic void run() {// 使用死循环 让买票重复执行while (true) {l.lock();try {// 先判断票是否存在if (ticket > 0) {// 提高安全问题出现的概率,让程序睡眠try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//票存在 ticket---System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");ticket--;}} finally {l.unlock(); // 无论程序是否异常,都会将锁对象释放}}}}
