java 线程安全的问题 详解
原创
©著作权归作者所有:来自51CTO博客作者json____的原创作品,请联系作者获取转载授权,否则将追究法律责任
package com.day5.test;
/**
* User: Json
* Date: 2021/8/15
* 线程的同步
* 解决 多个线程执行的不确定性引起执行结果的不稳定
* 解决的问题点:
* 多个线程对数据共享时 会造成操作的不完整性 会破坏数据
* 比如有3000块钱
* 你和你女朋友同时取1000 就会出现线程安全问题
* 解决方式
* 方式一 同步代码块
* synchronized(同步监视器){
* //需要被同步的代码
* }
* 说明: 1.操作共享数据的代码 即为需要被同步的代码 -->synchronized 不能包代码多了 也不能包多了
* 2. 同步监视器 , 俗称: 锁 任何一个类的对象, 都可以充当锁
* 要求:多个线程必须要共用同一把锁
* 创建多线程有两种方式
* 第一种 是继承Thread 类实现
* 这一种 必须声明一个静态的对象属性 充当锁 如果不是 多线程就用的不是一把锁了
* 第二种 实现Runnable接口的方法 来实现
* 这一种 可以直接 声明普通的对象属性 来充当锁
* 这种 还可以使用 this 充当 对象 就不用声明 一个对象
* 一定要保证 锁 是唯一的 要么还会存在线程安全问题
* //把练习的 卖票程序 synchronized包起来
* 例: synchronized (obj){
* // synchronized (this){
* if(num>0){
*
* System.out.println(java.lang.Thread.currentThread().getName()+"卖票 票号为"+num);
* num--;
* }else{
* break;
* }
*
* }
* 方式二 同步方法
* 如果操作共享数据的代码完整的声明在一个方法中 我们就可以把这个方法声明成 同步方法 来解决 线程安全问题
* 例: 还是使用 练习题中的 卖票的程序 做例子
* // 把卖票的过程 提取出来给他声明成一个独立的方法 加上synchronized 关键字即可
* 如果是使用 继承Thread类来实现的多线程 也必须把这个方法声明成静态的 static
* 使用实现Runnable接口的方法 就不需要了
* private synchronized void show(){
* if(num>0){
*
* System.out.println(java.lang.Thread.currentThread().getName()+"卖票 票号为"+num);
* num--;
* }
* }
*
*
* 方式一 解决了线程安全问题
* 但是 在操作代码时 只有一个线程参与 其他线程等待 相当于是一个单线程执行的过程 效率低
**/
public class Synchronization {
}
package com.day6.test;
import java.util.concurrent.locks.ReentrantLock;
/**
* User: Json
* Date: 2021/8/18
* 解决线程安全问题 方式三 * jdk5.0 新增
* 1. synchronized 和Lock 的异同
* 相同:二者都可以解决线程安全问题
* 不同:synchronized 机制在执行完相应的同步代码以后,自动释放锁
* Lock 需要手动启动 结束时也需要手动结束
* jdk5.0 新增
**/
public class LockTest implements Runnable{
private int num=100;
// 1. 实例化 ReentrantLock
// 如果 给这个对象 传 true 就是公平模式 一个进程执行一次
// 确保唯一性 如果使用继承的方式
private ReentrantLock lock=new ReentrantLock(true);
@Override
public void run() {
while (true){
try {
//2.调用lock;
lock.lock();
if(num>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票:"+num);
num--;
}else{
break;
}
}finally {
//3. 调用解锁方法
lock.unlock();
}
}
}
}