重学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加了死锁是线程安全,线程同步的

相关推荐
吾日三省吾码6 分钟前
JVM 性能调优
java
stm 学习ing11 分钟前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga
湫ccc1 小时前
《Python基础》之字符串格式化输出
开发语言·python
弗拉唐1 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi772 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
mqiqe2 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
AttackingLin2 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
少说多做3432 小时前
Android 不同情况下使用 runOnUiThread
android·java