重学java 39.多线程 — 线程安全

逐渐成为一个情绪稳定且安静成长的人

------24.5.24

线程安全

什么时候发生?

当多个线程访问同一个资源时,导致了数据有问题,出现并发 问题,数据不能及时更新,导致数据发生错误,出现线程安全问题

多线程安全问题示例

java 复制代码
package S71ThreadSafe;

public class MyTicket implements Runnable{
    // 定义100章票
    int ticket = 100;
    @Override
    public void run(){
        while(true){
            if(ticket>0){
                System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");
                ticket--;
            }
        }
    }
}
java 复制代码
package S71ThreadSafe;

public class Demo210Test {
    public static void main(String[] args) {
        // new一次,分别传递到三个线程对象中去
        MyTicket myTicket = new MyTicket();

        Thread th1= new Thread(myTicket, "赵四");
        Thread th2= new Thread(myTicket, "刘能");
        Thread th3= new Thread(myTicket, "广坤");

        th1.start();
        th2.start();
        th3.start();
    }
}

解决线程安全问题方式一:同步代码块

synchronized代码块 == 上锁 可以解决线程安全问题,不保证线程顺序

1.格式:

synchronized(任意接收对象){

线程要执行的语句;

}

2.任意对象:

就是我们的锁对象

3.执行:

一个线程拿到锁之后,会进入到同步代码块中执行,在此期间,其他线程拿不到锁,就进不去同步代码块。需要在同步代码块外面等待排队,需要等待执行的线程执行完毕,出了同步代码块,相当于释放锁了,等待的线程才能抢到锁,才能进入到同步代码块中执行,上的锁必须是同一个锁对象,同一把锁

java 复制代码
package S71ThreadSafe;

import java.util.Scanner;

public class MyTicket implements Runnable{
    // 定义100章票
    int ticket = 100;

    // 任意new一个对象
    Object obj = new Object();
    Scanner sc = new Scanner(System.in);

    @Override
    public void run(){
        while(true){
            synchronized (sc) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
                    ticket--;
                }
            }
        }
    }
}
java 复制代码
package S71ThreadSafe;

public class Demo210Test {
    public static void main(String[] args) {
        // new一次,分别传递到三个线程对象中去
        MyTicket myTicket = new MyTicket();

        Thread th1= new Thread(myTicket, "赵四");
        Thread th2= new Thread(myTicket, "刘能");
        Thread th3= new Thread(myTicket, "广坤");

        th1.start();
        th2.start();
        th3.start();
    }
}

解决线程安全问题方式二:同步方法

1.普通同步方法_非静态

在普通方法内用一个同步代码块

① 格式:

修饰符 synchronized 返回值类型 方法名(参数){

方法体

return 结果

}

② 默认锁:

this

java 复制代码
package S73ThreadSafeSolve2;

public class Demo212Test {
    public static void main(String[] args) {
        // new一次,分别传递到三个线程对象中去
        MyTicket myTicket = new MyTicket();
        System.out.println(myTicket);

        Thread th1= new Thread(myTicket, "赵四");
        Thread th2= new Thread(myTicket, "刘能");
        Thread th3= new Thread(myTicket, "广坤");

        th1.start();
        th2.start();
        th3.start();
    }
}
java 复制代码
package S73ThreadSafeSolve2;

import java.util.Scanner;

public class MyTicket implements Runnable{
    // 定义100章票
    int ticket = 100;

    Scanner sc = new Scanner(System.in);

    @Override
    public void run(){
        while(true){
            try{
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // 调用同步方法
            // method01();
            method02();
        }
    }

    // 定义一个同步方法
    public synchronized void method01(){
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
            ticket--;
        }
    }

    // 在普通方法内用一个同步代码块
    public void method02(){
        synchronized (this){
            System.out.println(this+"------------------------------------------------------------");
            if (ticket>0){
                System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
                ticket--;
            }
        }
    }

}

只new了一次对象

2.静态同步方法

① 格式

修饰符 static synchronized 返回值类型 方法名(参数){

方法体

return 结果

}

② 默认锁

class对象

java 复制代码
package S74ThreadSafeSolve3;

import java.util.Scanner;

public class MyTicket implements Runnable{
    // 定义100章票
    static int ticket = 100;

    Scanner sc = new Scanner(System.in);

    @Override
    public void run(){
        while(true){
            try{
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // 调用同步方法
            method02();
        }
    }

    // 在普通方法内用一个同步代码块
    public static void method02(){
        synchronized (MyTicket.class){
            if (ticket>0){
                System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
                ticket--;
            }
        }
    }

}
java 复制代码
package S74ThreadSafeSolve3;

public class Demo213Test {
    public static void main(String[] args) {
        // new一次,分别传递到三个线程对象中去
        MyTicket myTicket = new MyTicket();
        System.out.println(myTicket);

        Thread th1= new Thread(myTicket, "赵四");
        Thread th2= new Thread(myTicket, "刘能");
        Thread th3= new Thread(myTicket, "广坤");

        th1.start();
        th2.start();
        th3.start();
    }
}

StringBuider是线程不安全的,StringBuffer加了死锁是线程安全,线程同步的

相关推荐
yaoxin5211236 小时前
434. Java 日期时间 API - Period 基于日期的时间段
java·开发语言·python
凡人叶枫6 小时前
Effective C++ 条款30:透彻了解 inlining 的里里外外
linux·开发语言·c++·嵌入式开发·effective c++
学逆向的7 小时前
C++纯虚函数
开发语言·c++·网络安全
何极光7 小时前
IDEA集成Maven
java·maven·intellij-idea
程序员二叉7 小时前
【JUC】ThreadLocal底层原理|内存泄漏|弱引用|跨线程传递方案
java·开发语言·面试·职场和发展·juc
程序员二叉7 小时前
【JUC】线程池全套深度详解|参数|流程|拒绝策略|调优|异常处理
java·开发语言·jvm·算法·面试·juc
老马识途2.07 小时前
在AI的帮助下理解spring的启动过程
java·前端·spring
青山木7 小时前
Hot 100 --- 轮转数组
java·数据结构·算法
凡人叶枫8 小时前
Effective C++ 条款22:将成员变量声明为 private
linux·开发语言·c++
Qt程序员8 小时前
掌握 Linux 内核调度:从原理到实现(进程篇)
java·开发语言