首页 存档 技术 查看内容

Java中的多线程

2018-3-30 13:00 |来自: 互联网 270 0

摘要: 引 如果对什么是线程、什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内。 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只 ...



如果对什么是线程、什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内。


用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。


很多人都对其中的一些概念不够明确,如同步、并发等等,让我们先建立一个数据字典,以免产生误会。


  • 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程

  • 并行与并发:

    • 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。

    • 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。



并发与并行


  • 线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码:

oid transferMoney(User from, User to, float amount){
 to.setMoney(to.getBalance()   amount);
 from.setMoney(from.getBalance() - amount);
}
  • 同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。


好了,让我们开始吧。我准备分成几部分来总结涉及到多线程的内容:


1、扎好马步:线程的状态

2、每个对象都有的方法(机制)

3、太祖长拳:基本线程类

4、九阴真经:高级多线程控制类


扎好马步:线程的状态


先来两张图:



线程状态



线程状态转换


各种状态一目了然,值得一提的是"blocked"这个状态:


线程在Running的过程中可能会遇到阻塞(Blocked)情况



1、调用join()和sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待JVM的调度。


2、调用wait(),使该线程处于等待池(wait blocked pool),直到notify()/notifyAll(),线程被唤醒被放到锁定池(lock blocked pool ),释放同步锁使线程回到可运行状态(Runnable)


3、对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool ),同步锁被释放进入可运行状态(Runnable)。


此外,在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。Thread类中的yield方法可以让一个running状态的线程转入runnable。


内功心法:每个对象都有的方法(机制)


synchronized, wait, notify 是任何对象都具有的同步工具。让我们先来了解他们



monitor


他们是应用于同步问题的人工线程调度工具。讲其本质,首先就要明确monitor的概念,Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。


wait/notify必须存在于synchronized块中。并且,这三个关键字针对的是同一个监视器(某对象的监视器)。这意味着wait之后,其他线程可以进入同步块执行。


当某代码并不持有监视器的使用权时(如图中5的状态,即脱离同步块)去wait或notify,会抛出java.lang.IllegalMonitorStateException。也包括在synchronized块中去调用另一个对象的wait/notify,因为不同对象的监视器不同,同样会抛出此异常。


再讲用法:


  • synchronized单独使用:

    • 代码块:如下,在多线程环境下,synchronized块中的方法获取了lock实例的monitor,如果实例相同,那么只有一个线程能执行该块内容

public class Thread1 implements Runnable {
Object lock; public void run() { synchronized(lock){ ..do something } } }
    • 直接用于方法: 相当于上面代码中用lock来锁定的效果,实际获取的是Thread1类的monitor。更进一步,如果修饰的是static方法,则锁定该类所有实例。

public class Thread1 implements Runnable {
  public synchronized void run() { 
    ..do something
  }
}
  • synchronized, wait, notify结合:典型场景生产者消费者问题

/**
  * 生产者生产出来的产品交给店员
  */
 public synchronized void produce()
 {   if(this.product
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部