多线程基础---线程安全(原因及解决方法),synchronized,volatile关键字

目录

1. 中断线程

2. 线程等待

3. 守护线程

4. Java中的线程状态

5. 线程安全

1) 背景/原因

2) 线程安全的解决

6.  synchronized 同步关键字

7.  volatile


1. 中断线程

1) 使用标志位的方式

isStop变量.

public class FlagStop {
    private static volatile boolean isStop;

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (!isStop) {
                        System.out.println("转账....");
                        Thread.sleep(1000);
                    }
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }).start();
        //停止转账
        Thread.sleep(3000);
        isStop=true;
    }
}

2) 线程中断的API

前置: 线程Thread中,存在一个中断标志位,默认值=false(没有被中断)

   

     

      

public class InterruptThread {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while(!Thread.currentThread().isInterrupted()){
                        System.out.println("转账...");
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        Thread.sleep(3000);
        t.interrupt();
    }
}

2. 线程等待

1)  API

线程引用对象.join()     /    线程引用对象.join(long)

当前线程阻塞等待,直到满足以下条件:

无参: 线程引用执行完毕

有参: 等待指定时间,或者线程引用执行完毕,任意一个条件满足,当前线程继续向下执行.

2) 示例

public class LearnJoin {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    System.out.println("t start");
                    Thread.sleep(5000);
                    System.out.println("t end");
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        });
        t.start();
        t.join(2000);
        System.out.println("main");
    }
}

3. 守护线程

1) API

参数为:

true: 设置为守护线程;

false: 设置为用户线程.

2) 一个Java进程,至少有一个用户线程存在,才会运行,否则就结束.

4. Java中的线程状态

这里的等待,超时等待,阻塞状态,和之前学习的进程状态转换图,阻塞状态,表现是一样的,线程暂停/挂起.

5. 线程安全

1) 背景/原因

代码层面上: 多个线程对同一个共享数据的操作(读,写),如果有写操作,就存在线程安全问题.

底层的原因: 原子性,可见性,有序性.

① 原子性

  • 一系列的操作(多行代码指令的执行),需要具有不可分割的特性,就是原子性.
  • 如果可以被分割,指令之间,可能有其他线程并发并行执行的操作,对同一个共享变量操作就会产生影响.

特殊的非原子性操作:

a) n++,n--,++n,--n

           从主存把数据读取到CPU  (读)

   进行数据的更新  (改)

   把数据写回到主存  (写回)

b) new一个对象

       

        一行new对象的代码,分解为:

        I. 分配内存空间(Java虚拟机)

       II. 执行构造方法(字节码层面的<init>构造方法: 收集成员变量,实例代码块,Java代码中的构造方法)

      III. 把new的对象赋值给变量

② 可见性

线程对主存数据的操作,需要先加载到线程私有的工作内存,操作完再写回到主存,线程之间的工作内存,是互相不可见的.

       

共享变量,存储于主存(线程共享区域),线程对变量的操作:

a) 加载到工作内存

b) 操作(赋值,修改)

c) 写回主存

③ 重排序

多行指令(字节码指令在Java虚拟机执行,及机器码指令在CPU执行)在执行时,可能进行优化(目的是提高执行效率),只是不能重排序有关联的指令.

比如洗苹果,吃苹果,这两条指令由于具有前后关系,所以就不能重排序.洗苹果,洗梨,就可以进行重排序.

2) 线程安全的解决

线程安全,是由于多个线程对共享变量的操作,并发并行执行的结果.(共享变量称为临界资源,这种代码(多行),称为临界区)

思路: 临界区代码执行时,先申请jvm加锁,然后再执行. 申请锁,是需要同一把锁来保证线程安全;申请失败,线程则需要等待(可以是阻塞式的,也可以是非阻塞式)

这种操作,在多个线程执行临界区都申请同一把锁的情况下,多个线程运行的结果,就表现为: 多个线程,依次执行临界区代码.

假如现在我(线程)----申请把餐厅101包间加锁---吃饭,喝水(临界区: 此时作为不可分割的最小执行单位)----归还锁---通知其他要在101做事的人(其他线程)---重复以上流程.

6.  synchronized 同步关键字

1) 作用:

基于对象头加锁的方式,只要申请同一把锁加锁的线程,都有同步互斥的作用.

  • 对象: 某个对象加锁(本质是对象在内存中的对象头加锁)
  • 同一把锁: 是否为同一个对象加锁.
  • 同步互斥: 多个线程之间执行synchronized作用域范围的临界区代码,是一个一个依次执行.

2) 语法:

  • ①静态同步方法: 使用的锁为当前的类对象
  • ②实例同步方法: 使用的锁为当前调用的实例对象(this)
  • ③同步代码块: 使用的锁,为小括号中的对象

语法上对应申请锁-----加锁----释放锁

synchronized代码行: 线程申请某个对象锁

synchronized作用域结束(花括号结束): 自动释放对象锁.

3) 特别注意的事项:

多线程只有申请同一个对象的加锁,才具有同步互斥的效果.

不是对同一个对象加锁,并发并行的执行.(部分A加同一把锁,部分B不加锁,A中的多个线程同步互斥,但是B和A,B内部的多个线程,都是并发并行)

7.  volatile

1) 作用

①保证变量(分解为字节码以后的)的可见性.

②建立一个内存屏障,禁止指令重排序.

2) 使用场景:

代码行本身保证原子性的前提下,变量使用volatile修饰,可以保证线程安全.

关于代码行本身保证原子性的理解:

①读(从主存读取到线程的工作内存)

②修改为一个常量值(把常量值写回主存)

 

 

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值