JAVA-多进程3

一.线程的状态

1.1 观察线程的所有状态

  • NEW:安排工作,还未开始行动 (Thread对象创建好了,但是还没有调用start方法)
  • (就绪状态)RUNNABLE:可工作的,又可以分为正在工作和即将开始工作
  • (阻塞状态)BLOCKED:这几个都表示排队等着其他事情(因为锁产生了阻塞)
  • (阻塞状态)WAITING:这几个都表示排队等着其他事情(因为调用了wait产生了阻塞了)
  • (阻塞状态)TIME_WAITING:这几个都表示排队等着其他事情(因为sleep产生阻塞)
  • TERMINATED:工作完成了

就绪状态:可理解成两种情况

1)线程正在CPU上运行

2)线程在这里排队,随时都可以去排队

  •  sleep阻塞前: 
package thread;

public class Demo11 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(() ->{
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        });

        System.out.println(t.getState());
        //获取当前线程之前的状态
        t.start();

        t.join();//等待上述t线程执行结束
        System.out.println(t.getState());
        //获取当前线程结束过后的状态
    }
}

  • sleep阻塞后: 
package thread;

public class Demo11 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(() ->{
            while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        System.out.println(t.getState());
        //获取当前线程之前的状态
        t.start();

        Thread.sleep(1000);
        System.out.println(t.getState());
        //获取当前线程结束过后的状态
    }
}

 


1.2 线程安全

例:两个线程,针对同一个变量,进行循环自增,各自自增5万次,预期最终为十万次,但实际上并不是(产生bug)

        在多线程下,发生由于多线程执行导致的bug,统称为“线程安全问题”,如果某个代码在单线程下执行也没有问题,多个线程下执行也没有问题,则称为“线程安全,反之也可以称为“线程不安全”

有问题的代码

package thread;

class Counter{
    public int count=0;
    public void increase(){
        count++;
    }
}

public class Demo12 {
    public static void main(String[] args) throws InterruptedException {
        Counter counter=new Counter();

        Thread t1=new Thread(() ->{
            for(int i=0;i<50000;i++){
                counter.increase();
            }
        });

        Thread t2=new Thread(() ->{
            for(int i=0;i<50000;i++){
                counter.increase();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(counter.count);
    }
}

第一次运行结果

 第二次运行结果

第三次运行结果

  


线程安全的根本原因:

1.【根本原因】:多个线程之间的调度顺序是“随机的”,操作系统使用“抢占式”执行的策略来调度线程

        和单线程不同的是,多线程下,代码的执行顺序产生了更多的变化

        以往只需要考虑代码在一个固定的顺序下执行,执行正确即可,现在则需要考虑多线程下,N种执行顺序下,代码执行结果都得正确

2.多个线程同时修改同一个变量,容易产生线程安全问题

        一个线程改变一个变量,没事

        多个线程读取同一个变量,没事

        多个线程修改多个变量,没事

3.进行的修改,不是“原子的”,即不可拆分的例count++就不是原子的

        如果修改操作,能够按照原子的方式来完成,此时也不会有线程安全问题

        =直接赋值,视为原子        if=先判定,再赋值,也不是原子

解决线程问题,最主要的切入手段:

        加锁 => 相当于是把一组操作,给打包成一个“原子”的操作

        事务的原子操作,主要是靠回滚

        此处的原子则是通过锁,进行“互斥”

        这个线程进行工作时,其他线程无法进行工作

4.内存可见性,引起的线程安全问题

5.指令重排序,引起的线程安全问题


解决方案

        在对count++的时候进行加锁操作

        java引入了一个synchronized关键字

        使用方法:直接在方法前加关键字

        进入方法就会加锁,结束方法就会解锁

        加锁的目的是为了互斥使用资源(互斥的修改变量)

package thread;

class Counter{
    public int count=0;
     synchronized public void increase(){
        count++;
    }
}

public class Demo12 {
    public static void main(String[] args) throws InterruptedException {
        Counter counter=new Counter();

        Thread t1=new Thread(() ->{
            for(int i=0;i<50000;i++){
                counter.increase();
            }
        });

        Thread t2=new Thread(() ->{
            for(int i=0;i<50000;i++){
                counter.increase();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(counter.count);
    }
}


难点理解

        如果两个线程针对同一个对象进行加锁,就会出现 锁竞争/锁冲突 (一个线程能加锁成功,另一个线程阻塞等待)

理解:就是两个线程对同一个对象加锁,其中一个线程执行加锁中的代码块时,另外一个线程则会陷入等待的状况,不会执行加锁同一个的对象中的代码块

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值