简述

Java是支持多线程编程的语言,线程相比于进程更加轻量级,线程共享相同的内存空间,但是拥有独立的栈。减少了进程建立、销毁的资源消耗。jdk1.5后对java的多线程编程提供了更完善的支持,使得java的多线程编程更加方便简洁。本文旨在通过对Java多线程知识的梳理,整理出一个大纲,使得读者对多线程的编程有更加完善的认识。

线程生命周期的管理

  • 线程的创建

    java中线程的创建主要有两种方式:
  1. 继承Thread类(Thread中方法主要用于针对线程本身的处理);
  2. 实现Runnable接口;
  • 线程的通讯

    线程之间的通讯实际上是线程之间传递参数的问题。
  1. 往线程中传递参数: 通过新建线程的构造函数;
  2. 线程执行中,往外界传递参数:
    • 通过方法的返回值,但可能线程未执行完成,所以返回NULL。所以,用轮询的方式,获取方法返回值。

      缺点是浪费CPU周期。
    • 通过注册回调方法,在构造线程的时候传入回调类,然后,在线程执行过程中调用回调方法。
    • JDK1.5,提供了Future、Callable和Executor,Executor子类ExecutorService创建线程,实现Callable接口作为回调方法(实现call()方法),返回一个Future类。
  • 线程同步

    当多线程共享资源时,必须考虑同步问题。可以用synchronized关键字标注关键对象或方法。但是,同步不仅影响性能,同步的越多越容易造成死锁问题。(死锁:两个线程想要独占某种资源,但是,两者同时占用这种资源的子集的情况)

    同步的替代方法:

  1. 尽可能使用局部变量而不是字段,基本类型传参是值传递,是线程安全的(String也是安全的,一旦创建不能更改);
  2. 构造函数一般不需要考虑线程安全问题;
  3. 将非线程安全的类作为线程安全类的一个私有字段;

注:多线程中使用System.out输出,也属于共享资源。

  • 线程的调度

    JVM的线程调度器,抢占式的(preemptive)和协作式的(cooperative)。由于一个线程长时间占用CPU,会造成其他线程的饥饿状况。可以通过设置线程的优先级来改变这种情况,但是,在相同优先级的线程中,需要使用如下6种类方法,手动控制:
  1. 对I/O阻塞;
  2. 放弃,调用Thread.yield(),提供给相同优先级的线程CPU的使用机会;
  3. 休眠,sleep(),提供给相同优先级及以下优先级CPU的使用机会;
  4. 连接线程,join(),等待某个指定线程执行结束,或者执行一段时间;
  5. 等待某个对象,wait(),放弃对一个对象的锁定并暂停(之前的方法并不会放弃资源);
  6. 结束,方法返回return;

线程池

dk1.5对线程池提供了很好的支持。线程池的建立主要是为了减少内存资源的损耗,减少线程新建和删除的损耗,通过将任务(特定的线程)放置到队列中,然后,使用不同的策略,利用线程池中的线程处理队列中的任务。

ExecutorService调用一个基础API创建线程池,通过不同队列实现不同特性的线程池。队列是独立于线程池的一部分,用于放置线程池中未及时处理的任务。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* 线程池包装
*/
public class BearThreadPool { private ExecutorService pool; public void createCachedThreadPool(){
pool = Executors.newCachedThreadPool();
} public void addTask(Runnable task){
pool.submit(task);
} public void termination(){
pool.shutdown();
}
} /**
* 线程
*/
public class Task implements Runnable { private String taskId;
private TaskCallBack callback;
public Task(String taskId, TaskCallBack callback){
this.taskId = taskId;
this.callback = callback;
} public void run() {
synchronized (System.out){
System.out.println(taskId);
callback.before();
callback.middle();
callback.after();
System.out.println("==========");
} }
} /**
* 回调函数接口
*/
public interface TaskCallBack { void before(); void middle(); void after(); }

Java多线程小结的更多相关文章

  1. 【Java基础】Java多线程小结

    在说多线程之前,首先要清楚为啥要提出多线程,这就要明白线程和进程间的区别了. 线程和进程间的区别 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单 ...

  2. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

  3. java多线程(精华版)

    在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为 Java 编程语言提供了语言级的支持.本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观.读完本文以后,用户应 ...

  4. Java多线程---同步与锁

    一,线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 二.同步和锁定 1.锁的原理 Java中每个对象都有一个内置锁. 当程序运行到非静态的synchronized同步方法上时,自动 ...

  5. Java多线程-线程的同步与锁

    一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏.例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. package ...

  6. Java多线程的实现

    记得面试的时候,面试官问了Java多线程实现的方式有几种,它们之间的区别是什么?作为一个Java新手,将最近的学习总结如下: 1.Java多线程实现方式 Java多线程实现方式主要有三种:继承Thre ...

  7. 【Java多线程】两种基本实现框架

    Java多线程学习1——两种基本实现框架 一.前言 当一个Java程序启动的时候,一个线程就立刻启动,改程序通常也被我们称作程序的主线程.其他所有的子线程都是由主线程产生的.主线程是程序开始就执行的, ...

  8. Java多线程详解

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  9. Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)

    一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...

随机推荐

  1. 006 Python的操作符

      算术操作符: +    -    *    /       %    **    // 如 >>> a = 5 >>> a = a + 3 >>&g ...

  2. Razor引擎总结

    1.显示格式化小数:@(string.Format("{0:0.00}",ViewData["TradeAmount"].ToNullString()))

  3. C# aspnetpager分页

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs& ...

  4. 推送 -- error:Not get deviceToken yet

    获取不到devicetoken请检查: 1)     请检查你的pushconfig里的appkey与应用详情中是否一致 2)     bundleid有3处需要检查是否一致:a.你的应用详情中的bu ...

  5. 解决CocoaPods在OS X 10.11出现问题-b

    最近把mac系统升级到10.11系统,但是在用pod install命令的时候,却提示command not found.后来上网查了下才知道,Cocoapods在10.11系统上发生了变化. 在st ...

  6. C++中二维数组的动态创建与处理

    C++中用new动态创建二维数组的格式一般是这样: TYPE (*p)[N] = new TYPE [][N]; 其中,TYPE是某种类型,N是二维数组的列数.采用这种格式,列数必须指出,而行数无需指 ...

  7. [原博客] POJ 2975 Nim 统计必胜走法个数

    题目链接题意介绍了一遍Nim取石子游戏,可以看上一篇文章详细介绍.问当前状态的必胜走法个数,也就是走到必败状态的方法数. 我们设sg为所有个数的Xor值.首先如果sg==0,它不可能有必胜走法,输出0 ...

  8. 【技术帖】解决 Hudson jenkins 连接等待中 - Waiting for next av

    今天构建项目发现如下问题: jenkins 连接等待中 - Waiting for next available executor 左下角那块一直不运行构建,一直在连接等待. 于是,进入一级页面, 右 ...

  9. ECMall系统请求跳转分析

    ecmall是一个基于mvc模式框架系统,跟thinkphp有点像.先从ecmall的入口开始,ecmall入口文件upload/index.php.admin.php: index.php启动ecm ...

  10. JENKINS里,如何为SLAVE配置多个不同的JAVA环境?

    今天遇到这个问题了, 原来在MASTER配置里可以统一管理的,不管这个路径有没有在MASTER上. 这样一来,JENKINS在编译时,会优先选用环境变量里的JAVA版本,然后才是MAVEN里的JAVA ...