Java 多线程之基础

进程:程序执行的动态过程,持有资源和线程。

线程:系统中最小的执行单元,一个进程可以有多个线程,这些线程共享进程中的资源。​

临界区:一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。

java实现多线程有两个方法:继承Thread类或者实现Runnable接口,无论使用哪种方法都需要重写或实现其run()方法。​


Thread类中的方法:​

sleep():休眠,使线程的执行慢下来。(​Thread.sleep(2000);)

yield():使线程让出资源,其他线程获得资源而执行。(Thread.yield();​)

join():停止其他所有线程,使调用该方法的线程独立执行,不受干扰。(keyPerson.join();keyPerson为一个线程)


错误停止线程的方法:

stop():并不能很好地停止线程,出现一段空白,看不清线程执行了什么,什么没有被执行,已被​标注@deprecated。

interrupt():并不能停止线程,只是中断线程。若程序在执行其他方法如Thread的sleep(),Object的wait()受到阻塞,则其中断状态将被清除,它还将收到一个InterruptedException,因此在将要中断的线程的run()中,若调用了sleep()等可能造成阻塞的方法,则循环判断的条件不能是while(!isInterrupted()),如下面的程序应该使用红色部分标注的代码来替换sleep():​

    public void run() {

        while(!isInterrupted()){

            System.out.println("Thread is running...");

            long time =System.currentTimeMillis();

            while(System.currentTimeMillis() -time < 1000){

            }

        }

    }​

 

正确停止线程的方法:​

设置停止标志,如:​

    volatile booleankeepRunning = true;

    @Override

    public void run() {

        while(keepRunning){

            for(int i = 0; i < 5; i++){

                System.out.println(Thread.currentThread().getName() + "第[" + i +"]次进攻");

             }

        }

        System.out.println(Thread.currentThread().getName() +"结束战斗!");

    }​

注意,这里声明停止标志位volatile类型,以保证任何一个线程对其的操作都能及时反应回来。volatile 变量对所有线程是立即可见的,对 volatile变量所有的写操作都能立即反应到其他线程之中。保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的


线程的同步与互斥:

争用条件(RaceCondition):当多个线程同时共享访问同一数据(内存区域)时,每个线程都尝试操作该数据,从而导致数据被破坏的现象。

如:某一账户中存有1000块钱,有两个人A、B同时对这一账户作存钱操作,A首先抢占到CPU资源,复制账户中存款1000块钱加入到自己的线程内存中,加入要存的100块钱,但是还没来得及写回账户内存时便失去CPU资源。此时B抢占到资源,同样从账户内存中复制1000块钱到自己的线程内存中,加入要存的200块钱,将总额1200写回账户内存,此时A又获得CPU资源,继续完成之前未完成的操作,将自己存款总额1100块钱写回账户内存,这时,便覆盖了现在账户内存中的1200块钱,这样,本来最终正确的账户中是1300块钱,现在却只有1100块钱,这就造成了数据破坏,即争用条件。

互斥:同一时间只能做一件事情,同一时间只能执行一个线程。​

同步:一种通信机制,一个线程完成一件事,当他完成这件事的时候,用某种方式告诉其他线程自己已经做完了,已经让出CPU,让其他线程去执行。​

互斥实现synchronized加锁​​​

同步实现:wait()/notify()、notifyAll()(Object的成员函数)

private final Object lockObj= new Object();

synchronized(lockObj){​

    //使用While循环替换if

    //while循环,保证条件不满足时任务都会被条件阻挡,而不是继续竞争CPU资源

    while (energyBoxes[from] < amount){

        try{

            //条件不满足, 将当前线程放入Wait Set

            lockObj.wait();

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }​

    //需要互斥的业务行为

    System.out.print(Thread.currentThread().getName());

    energyBoxes[from] -= amount;

    System.out.printf("从%d转移.2f单位能量到%d", from, amount, to);

    energyBoxes[to] += amount;

    System.out.printf(" 能量总和:.2f%n", getTotalEnergies());

    //唤醒所有在lockObj对象上等待的线程,实现同步

    lockObj.notifyAll();

}

Wait Set:​

wait set是线程的集合;

当Java对象创建的时候,其wait set是空的。对于wait set操作(将线程加入或移出waitset)都是原子操作

对于waitset的操作(加入或移出),而且只能通过Object.wait,Object.notify,Object.notifyAll这三个操作来进行。当线程执行到Object.wait指令后,就会进入到waitset集合中;而执行到Object.notify,Object.notifyAll指令后,则通知处于waitset中的线程,条件满足了,他们的区别是notify()只随机通知一个线程,而notifyAll()则通知wait set中的所有线程。

 

 扩展

JMM(Java Memory Model) happens-before原则 synchronized,volatile​&final​

Locks&Condition:Java锁机制和等待条件的高层实现、java.util.concurrent.locks​

线程的安全性:原子性和可见性,java.util.concurrent.atomic实现原子性操作,synchronized&volatile​实现可见性编程,Deadline死锁

多线程编程常用的交互模型:​Producer-Consumer 模型、Read-WriteLock 模型、Future 模型、Worker Thread 模型​

Java 5并发编程工具:java.util.concurrent、线程池ExecutorService、Callable&Future、BlockingQueue

书籍:Core Java、Java Concurrency in Practice​

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值