初步了解线程安全

线程的状态:

Java中 Thread.State (内部定义的枚举) 只要把State的枚举带印出来

package package1213;

public class ThreadStateDemo {
    public static void main(String[] args) {
        Thread.State[] values = Thread.State.values();
        for (Thread.State state : values){
            System.out.println(state);
        }
    }
}

NEW // 创建
RUNNABLE//就绪+运行 状态
BLOCKED//阻塞
WAITING//阻塞
TIMED_WAITING//阻塞
TERMINATED//停止


线程安全:进程运行的结果和预期的一致,就是线程安全
类/对象线程安全:该类或者该对象在使用时,不需要你再考虑线程问题,认为他线程安全

package package1213;

public class UnsafeThread {
    private static int n = 0;
    private static class MyThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 5000; i++) {
                n++;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[5];
        for (int i = 0; i < 5; i++) {
            Thread t = new MyThread();
            t.start();
            threads[i] = t;
        }
        for (int i = 0; i < 5; i++) {
            threads[i].join();
        }
        System.out.println(n);
    }
}

执行多次的结果
20782
22817
24204
不是我们预期25000

出现问题的原因:
1.有共享数据才有可能出现线程安全问题.
2.线程的调用是随时发生的,无法预测


这里就要提一下Java的内存分配了:
PC/栈(Java栈/本地方法栈) 私有的
堆/方法区/常量池 共享的
而这段代码中的静态变量n就是再方法区中


多线程出问题的原因
1.线程之间交错运行
2.内存区域的数据不相等


原子性

以下是原子的
int a = 10;原则性
… 除了 double/long
变量 = 常量的 操作都是原子的

非原子性

n++一定不是原子
因为,它划分几条操作 int tmp = n ; tmp = tmp + 1; n =tmp;

  1. 从内存把数据读到 CPU
  2. 进行数据更新
  3. 把数据写回到 CPU

这里没加到25000,就是因为原子性问题

比如线程一执行了1,2步,此时n加到了1000,这时候他的时间片到了,cpu不调度他了
然后线程二进来了执行了1,2步加到了1500,但是他成功在cpu调度时间内走到了第三步,把1500写回了cpu,然后退出
这时候线程一进来了,走第三步把1000写回cpu,这时候线程2就白忙活了


1.模型分为主内存和工作内存,
2.主内存只有一份,(虚拟真实的内存)
3工作内存,每个线程各有一份(虚拟真实的cpu内存)
4.线程不可以直接操作主内存中的数据

 4.1.先load,把数据从之内存加载到工作内存
 4.2.修改工作内存中的数据
 4.3.合适的时候,把数据保存回主内存

Java内存区域划分是不同视角


大思路上,如何保证线程安全

  1. 如果涉及代码时,可以不进行数据共享,就尽量不数据共享 不用属性 + 静态属性没问题
  2. 如果非要共享数据,尽量使用数据的符本(复制出来的数据)/不可变对象 A传给B一份数据,如果B得到的数据只是一份复制,那数据其实也没有共享
  3. 确实要有数据共享了 做到三个保证: 原子/可见性/重排序

synchronized

synchronized用的锁是存在Java对象头里的。
在这里插入图片描述

synchronized void method() {} 
==等价  void method(){
        synchronized(this){}
    }
//普通方法的锁,锁的是当前对象
synchronized static void smethod() {
    synchronized(C.class){}
} 
//锁的是这个类的对象

正确写法

		@Override
        public void run() {
            for (int i = 0; i < 5000; i++) {
                synchronized (UnsafeThread.class){
                    //加个锁
                    n++;
                }
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值