一、线程控制

  和线程相关的操作都定义在Thread类中,但在运行时可以获得线程执行环境的信息。比如查看可用的处理器数目(这也行?):

public class RunTimeTest {
public static void main(String[] args) {
Runtime rt=Runtime.getRuntime();
System.out.println(rt.availableProcessors());
System.out.println(rt.totalMemory());
System.out.println(rt.freeMemory());
System.out.println(rt.maxMemory());
}
}

  以上程序的输出为:

  • JVM可用的处理器数量:8
  • JVM的内存总量:128974848
  • JVM的可用(free)内存量:125561424
  • JVM将尝试使用的最大内存量:1890582528

  线程还提供了一些方法用于对线程进行便捷的控制。

  1、线程睡眠

  静态方法Thread.sleep(long millis)强制正在执行的线程暂停进入睡眠状态,进入阻塞状态。睡眠结束后,线程转为就绪状态。

/*自定义的睡眠时间单位为毫秒*/
/*必须要进行异常处理*/
try {
Thread.sleep(lengthOfPause);
} catch(InterruptedException e) {
e.printStacktrace();
}

  值得强调的是:

  • 线程睡眠是帮助其他所有线程获得运行机会的最好方法;
  • 线程睡眠到期自动苏醒,并返回到就绪状态,不是运行状态。然后,sleep()中参数指定的时间是停止运行的最短时间,而无法保证从睡眠苏醒后就开始执行;
  • sleep()是静态方法,只能控制当前正在运行的线程;

  2、线程让步

  yield()方法使当前线程让出CPU占有权,与sleep()类似,但让出时间无法设定。而且yield()使线程进入就绪状态,更利于有同优先级的其它线程获得运行机会。只是实际中,无法保证yield()达到让步目的,比如让步的线程又被JVM选中。

  yield()方法不会释放锁标志。实际上,yield()方法对应了如下操作:先检测当前是否有相同优先级的线程处于就绪状态。若有,则把CPU占有权交给此线程;若没有,继续运行原来的线程。所以yield()尝试做的,是把运行机会给同等级的其它线程,而无法让低级别的线程获得。

  3、线程加入

  在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态。直到另一个线程运行结束,阻塞的线程重回就绪状态。

  join()是Thread类的非静态方法,还有带有超时限制的重载版本,如t.join(5000)是让线程等待5000ms,超时后,阻塞的进程进入就绪状态。

  4、线程优先级

  当应用启动时,主线程是创建的第一个用户线程,程序可以创建多个用户线程和守护线程。

  当所有的用户线程执行完毕,JVM终止进程。

  设置线程的优先级:

/*优先级为1~10*/
Thread t=new MyThread();
/*设置线程优先级*/
t.setPriority(8);
/*获取线程优先级*/
t.getPriority();
t.start(); //只是说优先级更高的线程有更多的机会获得运行,并不保证先于优先级低的线程运行。

  守护线程的优先级别是最低的,用于为系统中的其他对象和线程提供服务,例如JVM中的资源自动回收线程。

  将一个用户线程设置为守护线程的方法是在线程对象创建之前调用线程对线的setDaemon()方法。

  5、线程分组管理

  ThreadGroup类

  一旦线程加入某个线程组,该线程就一直存在于该线程组中直至死亡,不能中途改变线程所属的组。

  二、线程同步

  线程调度的意义在于,JVM对运行的多个线程进行系统级别的协调,以避免多个线程争夺有限的资源而导致应用崩溃。

  同步是一种防止对共享资源访问导致数据不一致的机制。即当多个线程访问同一个共享资源时,需要确保该资源在一段时间內仅被一个线程访问。

  1、锁机制

  锁机制限制在同一时间只允许一个线程访问产生竞争的临界区。

  关键字synchronized为代码块or方法加锁,实现同步。线程在使用临界资源时加锁,拒绝其他线程的访问,直至该线程解锁。

  实际上,任何对象都有一个监视器用于加锁和解锁,当synchronized声明的代码块or方法被执行时,说明当前线程已经成功获取了对象监视器上的锁。当正常执行完毕或异常退出时,当前线程所获取的锁会被自动释放

  线程可以在一个对象上加多次锁,JVM保证获取锁之前和释放锁之后的变量的值是与主存中的内容同步的。

  (1)同步方法(参考

  使用synchronized声明方法。

  当访问某个对象的同步方法,这个对象会加锁,而不是仅仅为该方法加锁!因此当对象的同步方法被某个线程执行时,其他线程无法访问该对象的任何同步方法,但是可以调用其它非同步方法。(即对象加锁,意味着所有的同步方法只能被持锁的线程访问)

  当调用一个对象的静态同步方法时,它锁定的不是同步方法所在对象,而是它对应的Class对象。因此,其他线程不能调用该类的其他静态同步方法,但是可以调用非静态同步方法。

  (2)同步代码块

  使用synchronized声明同步代码块,锁定其所在的对象or特定的对象,还对象作为可执行的标志从而达到同步效果。

/*同步代码块*/
public void method(){
synchronized(表达式){
}
}

  如果想要使用synchronized同步代码块达到和使用synchronized()方法同样的效果,可以锁定this引用:

synchronized(this){
...
}

  同步方法是一种粗粒度的并发控制,某一时刻只能有一个线程执行该同步方法。同步代码块是细粒度的并发控制,只会将块中的代码同步,代码块之外的代码可被其他线程同时访问。

  使用synchronized要注意:

  • synchronized关键字不能继承;
  • 定义接口方法时不能使用synchronized;
  • 构造方法不能使用synchronized关键字,但可以使用synchronized代码块进行同步;

  三、线程协作

  线程之间会有协作关系,一起来完成某项任务。如生产者—消费者模式。

  多线程可以通过访问和修改同一份资源(对象)来进行交互和通信,只是需要注意线程访问的安全性。当线程所要求的资源不足时,就进入等待状态;而另外的线程则负责在合适的时机发出通知来唤醒等待中的线程。

  等待—通知机制是完成线程间同步的基本机制。

  1、wait与notify原语

  在对象上调用wait()方法时,首先要检查当前线程是否获取到了该对象上的锁。若没有,会直接抛出IllegalMonitorStateException异常。如果有锁,就会把当前线程添加到对象的等待集合中,并释放其所拥有的锁,这样另一个线程就可以获得当前对象的锁,从而进入synchronized()方法中。

  sleep()和yeild()方法并不释放锁,调用wait()方法后,当前线程被阻塞,无法继续执行,知道被等待集合移除。

  引起某个线程从对象的等待集合中被移除的原因有:

  • 对象上的notify()方法被调用;
  • 对象上的notifyAll()方法被调用;
  • 线程被中断;
  • 对于有超时限制的wait操作,当超过时间限制时;

  从上面的说明中,总结三条结论:

  (1) wait/notify/notifyAll操作需要放在synchronized代码块或者方法中,这保证执行它们时,当前线程已经获得所需要的锁;

  (2) 当对象的等待集合中的线程数目无法确定时,最好使用notifyAll()方法而不是notify()方法;

  (3) notifyAll()方法会导致线程在没有必要的情况下被唤醒而产生性能影响,但是使用上更简单。

  由于线程可能在非正常情况下被意外唤醒,一般应把wait操作放在循环中检查所要求的逻辑条件是否满足。典型的使用形式:

/*使用一个私有的lock作为加锁的对象*/
/*好处是可以避免其它代码错误地使用这个对象*/
private Object lock=new Object();
synchronized(lock){
while(/*逻辑条件不满足时*/){
try{
lock.wait();
}catch(InterruptedException e){}
}
}

  2、生产者-消费者问题

  生产者-消费者问题是线程协作的典型方式,即生产者生产产品的速度和消费者消费的速度可能不匹配,产品超出库存能力,此时生产者必须等待,直到消费者消耗了产品。

  对应到线程协作中,就是线程间协调的“生产者-消费者-仓储”模型,生产者和消费者通过仓储通信,根据仓储容量和产品数目协同生产消费过程。

  wait()方法的使用,必须存在2个以上线程,而且必须在不同的条件下唤醒等待中的线程。

  四、线程池

  五、线程同步控制的新特征

Java 线程控制的更多相关文章

  1. java线程控制、状态同步、volatile、Thread.interupt以及ConcurrentLinkedQueue

    在有些严格的系统中,我们需要做到干净的停止线程并清理相关状态.涉及到这个主题会带出很多的相关点,简单的总结如下: 我们知道,在java中,有一个volatile关键字,其官方说明(https://do ...

  2. Java 线程控制(输出奇偶数)

    两个线程,一个输出1,3,5,7......99:另一个输出2,4,6,8......100. 1.线程同步 public class ST2 { int i = 0; public static v ...

  3. java线程控制安全

    synchronized() 在线程运行的时候,有时会出现线程安全问题例如:买票程序,有可能会出现不同窗口买同一张编号的票 运行如下代码: public class runable implement ...

  4. Java并发1——线程创建、启动、生命周期与线程控制

    内容提要: 线程与进程 为什么要使用多线程/进程?线程与进程的区别?线程对比进程的优势?Java中有多进程吗? 线程的创建与启动 线程的创建有哪几种方式?它们之间有什么区别? 线程的生命周期与线程控制 ...

  5. Java Thread线程控制

    一.线程和进程 进程是处于运行中的程序,具有一定的独立能力,进程是系统进行资源分配和调度的一个独立单位. 进程特征: A.独立性:进程是系统中独立存在的实体,可以拥有自己独立的资源,每个进程都拥有自己 ...

  6. 漫谈并发编程(二):java线程的创建与基本控制

    java线程的创建 定义任务           在java中使用任务这个名词来表示一个线程控制流的代码段,用Runnable接口来标记一个任务,该接口的run方法为线程运行的代码段. public ...

  7. Java中的线程状态转换和线程控制常用方法

    Java 中的线程状态转换: [注]:不是 start 之后就立刻开始执行, 只是就绪了(CPU 可能正在运行其他的线程). [注]:只有被 CPU 调度之后,线程才开始执行, 当 CPU 分配给你的 ...

  8. java多线程(六)线程控制类

    1.   多线程控制类 为了保证多线程的三个特性,Java引入了很多线程控制机制,下面介绍其中常用的几种: l  ThreadLocal l  原子类 l  Lock类 l  Volatile关键字 ...

  9. 浅谈 Java线程状态转换及控制

    线程的状态(系统层面) 一个线程被创建后就进入了线程的生命周期.在线程的生命周期中,共包括新建(New).就绪(Runnable).运行(Running).阻塞(Blocked)和死亡(Dead)这五 ...

随机推荐

  1. 20175329&20175313&20175318 2019-2020 《信息安全系统设计基础》实验三

    20175329&20175313&20175318 2019-2020 <信息安全系统设计基础>实验三

  2. mybatis用Map<Long,List<String>>作为参数

    mapper.xml文件里的<insert id="insertByMap" parameterType="java.util.Map"> inse ...

  3. Python 使用工具总结

    1.比较两个list大小:operator模块 operator.lt(a, b) operator.le(a, b) operator.eq(a, b) operator.ne(a, b) oper ...

  4. (转载)IOCP 浅析

    转自:http://www.ibm.com/developerworks/cn/java/j-lo-iocp/#author   郭 仁祥, 软件工程师, IBM 简介: 传统的 Server/Cli ...

  5. legend3---9、项目的日志以及调试信息数据量非常大

    legend3---9.项目的日志以及调试信息数据量非常大 一.总结 一句话总结: legend2我开发调试,最近竟然发现日志等的信息有1.5G,数据量实在太大 1.juqery如何找后代? chil ...

  6. 黑马vue---21-22、总结

    黑马vue---21-22.总结 一.总结 一句话总结: · 在 VM 实例中,如果要访问 data 上的数据,或者要访问 methods 中的方法, 必须带 this · 在 v-for 要会使用 ...

  7. ubuntu 14.04 升级到18.04

    http://www.360doc.com/content/18/0929/09/35082563_790606785.shtml

  8. antd源码分析之——标签页(tabs 2.Tabs关键组件功能实现)

    由于ant Tabs组件结构较复杂,共分三部分叙述,本文为目录中第二部分(高亮) 目录 一.组件结构 antd代码结构 rc-ant代码结构 1.组件树状结构 2.Context使用说明 3.rc-t ...

  9. vue-cli3.0 初体验

    vue-cli3.0 自我记录 其实在2018年8月10号,vue-cli3.0就已经面世了,由于项目中应用的全是2.x版本,所以并不了解3.0的vue-cli发生了什么变化,那今天尝试了下遇见的问题 ...

  10. 链接Linux工具(SecureCRT)

    SecureCRT下载 点我下载 http://download.csdn.net/download/weixin_39549656/10207279 安装 先运行注册机 链接 输入密码 出现以下界面 ...