并发编程可以使我们将程序划分为多个分离的,独立运行的任务。通过多线程机制,这些独立任务都将由执行线程来驱动。在使用线程时,CPU将轮流给每个任务分配占用时间,每个任务都觉得自己在占用CPU,但实际上CPU时间是划分为片段分配给了所有任务。

定义任务

继承Thread类

我们可以继承Thread类,并重写run方法。

  1. public class SimpleThread extends Thread {
  2. @Override
  3. public void run(){
  4. for(int i = 0; i < 5; i++){
  5. System.out.println(getName() + i);
  6. }
  7. }
  8.  
  9. public static void main(String[] args) {
  10. SimpleThread thread = new SimpleThread();
  11. thread.start();
  12. System.out.println(Thread.currentThread().getName());
  13. }
  14. }

实现Runnable接口

当然,我们还可以实现Runnable接口,并实现run接口,然后提交给Thread实例。

  1. public class Task implements Runnable{
  2. public void run(){
  3. for(int i = 0; i < 5; i++){
  4. System.out.println(Thread.currentThread().getName() + i);
  5. }
  6. }
  7. public static void main(String[] args) {
  8. Thread thread = new Thread(new Task());
  9. thread.start();
  10. System.out.println(Thread.currentThread().getName());
  11. }
  12. }

Callable与Future

我们知道run方法是没有返回值的,也就意味着任务完成后无法获取结果,所以我们需要Callable接口来帮助我们返回任务结果,它和Runnable接口很相似,所以我们也需要实现Callable接口的call方法。而Future接口则用来获取异步计算结果的,我们对执行结果获取,取消,或者判断是否完成。但是Callable接口并没有继承Runnable,所以并不能直接提交给Thread实例,所以我们还需要FutureTask类,它同时实现了Runnable接口和Callable接口,我们可以用FutureTask包装Callable对象,再提交给Thread实例。

  1. import java.util.concurrent.*;
  2.  
  3. public class TaskWithResult implements Callable<Integer> {
  4. public Integer call(){
  5. int total = 0;
  6. for(int i = 0; i < 100; i++){
  7. total += i;
  8. }
  9. return total;
  10. }
  11.  
  12. public static void main(String[] args) throws InterruptedException, ExecutionException{
  13. RunnableFuture<Integer> task = new FutureTask<Integer>(new TaskWithResult());
  14. Thread thread = new Thread(task);
  15. thread.start();
  16. while (!task.isDone()){
  17. System.out.println(task.get().toString());
  18. }
  19. }
  20. }

 后台线程

       后台线程,也叫守护线程,是指程序在运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。所以,当所有非后台线程结束时,后台线程也会被结束,不管后台线程是否完成。而且,后台线程的子线程也是后台线程。

  1. public class Daemon implements Runnable {
  2. @Override
  3. public void run() {
  4. for(int i = 0; i < 10; i++){
  5. try{
  6. Thread.sleep(1000);
  7. System.out.println(i);
  8. }catch (InterruptedException e){
  9. System.out.println(e.getMessage());
  10. }
  11. }
  12. }
  13.  
  14. public static void main(String[] args) throws InterruptedException{
  15. Thread thread = new Thread(new Daemon());
  16. thread.setDaemon(true);
  17. thread.start();
  18. Thread.sleep(1000 * 5);
  19. System.out.println(Thread.currentThread().getName());
  20. }
  21. }

这里要注意setDaemon方法必须要在start之前调用,才能将其设置为后台线程。

线程的生命周期

新建(new)

当线程被创建时,它只会短暂地处于这种状态。此时它已经分配了必须的系统资源,并执行了初始化。此刻线程已经有资格获得CPU时间了,之后调度器将把这个线程转变为可运行状态或阻塞状态。

就绪(Runnable)

在这种状态下,只要调度器把时间片分配给线程,线程就可以运行。也就是说,在任意时刻,线程可以运行也可以不运行。只要调度器能分配时间片给线程,它就可以运行,这不同于死亡和阻塞状态。

阻塞(Blocked)

线程能够运行,但有某个条件阻止它的运行。当线程处于阻塞状态时,调度器将忽略线程,不会分配给线程任何CPU时间。直到线程重新进入了就绪状态,它才有可能执行操作。

一个任务进入阻塞状态,可能有以下原因:

(1)通过调用sleep()使任务进入休眠状态,在这种情况下,任务在指定时间内不会运行。

(2)通过调用wait()使线程挂起。直到线程得到了notify()或notifyAll()消息,线程才会进入就绪状态。

(3)任务在等待某个输入/输出完成。

(4)任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另外一个任务已经获取了这个锁。

死亡(Dead)

处于死亡或终止状态的线程将不再是可调度的,并且再也不会得到CPU时间,它的任务已结束,或不再是可运行的。任务死亡的通常方式是从run()方法返回,但是任务的线程还可以被中断。

线程控制

线程优先级

线程的优先级将该线程的重要性传递给调度器。尽管CPU处理现有线程集的顺序是不确定的,但是调度器将倾向于让优先级最高的线程先执行。当然,这并不意味着优先权较低的线程将得不到执行(优先级不会导致死锁)。我们可以用getPriority()来读取现有线程的优先级,通过setPriority()来修改它。尽管JDK有10个优先级,但是它与多数操作系统都不能映射的很好。所以设置优先级时,一般使用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY三种级别。

休眠(Sleep)

在线程执行的过程中调用sleep方法让其休眠(也就是进入阻塞状态)。sleep会抛出InterruptedException。

  1. public class Sleep {
  2. public static void main(String[] args) {
  3. System.out.println("休眠开始");
  4. try{
  5. Thread.sleep(1000 * 2);
  6. }catch (InterruptedException e){
  7. System.out.println(e.getMessage());
  8. }
  9. System.out.println("休眠结束");
  10. }
  11. }

让步(Yield)

如果知道已经完成了run方法的循环的一次迭代过程中所需的工作,就可以给线程调度机制一个暗示:你的工作已经做的差不多了,可以让别的线程使用CPU了,这个

暗示将通过调用yeild作出,当然,这只是一种建议,没有任何机制保证它将会采纳。当线程切换出去后,只有优先级与当前线程相同,或优先级比当前线程更高的处于就绪的线程才会获得执行机会,因此完全有可能线程转入就绪后,调度器又将其调度出来重新执行。

Join
   join可以一个让线程等待另一个线程执行完成,调用线程将被阻塞,直到被join的线程执行完成。

  1. public class Task implements Runnable{
  2. public void run(){
  3. for(int i = 0; i < 5; i++){
  4. System.out.println(Thread.currentThread().getName() + i);
  5. }
  6. try{
  7. Thread.sleep(1000);
  8. }catch (InterruptedException e){
  9. System.out.println(e.getMessage());
  10. }
  11. }
  12. public static void main(String[] args) throws Exception{
  13. Thread thread = new Thread(new Task());
  14. thread.start();
  15. thread.join();
  16. System.out.println(Thread.currentThread().getName());
  17. }
  18. }

Java并发基础——Thread的更多相关文章

  1. Java并发基础--Thread类

    一.Thread类的构成 Thread类实现Runnable接口.部分源码如下: 二.Thread类常用方法 1.currentThread()方法 currentThread()方法可以返回代码段正 ...

  2. Java 并发基础

    Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...

  3. java并发基础(二)

    <java并发编程实战>终于读完4-7章了,感触很深,但是有些东西还没有吃透,先把已经理解的整理一下.java并发基础(一)是对前3章的总结.这里总结一下第4.5章的东西. 一.java监 ...

  4. java 并发编程——Thread 源码重新学习

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  5. Java并发基础概念

    Java并发基础概念 线程和进程 线程和进程都能实现并发,在java编程领域,线程是实现并发的主要方式 每个进程都有独立的运行环境,内存空间.进程的通信需要通过,pipline或者socket 线程共 ...

  6. java并发基础及原理

    java并发基础知识导图   一 java线程用法 1.1 线程使用方式 1.1.1 继承Thread类 继承Thread类的方式,无返回值,且由于java不支持多继承,继承Thread类后,无法再继 ...

  7. 【搞定 Java 并发面试】面试最常问的 Java 并发基础常见面试题总结!

    本文为 SnailClimb 的原创,目前已经收录自我开源的 JavaGuide 中(61.5 k Star![Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.欢迎 Sta ...

  8. java并发基础(五)--- 线程池的使用

    第8章介绍的是线程池的使用,直接进入正题. 一.线程饥饿死锁和饱和策略 1.线程饥饿死锁 在线程池中,如果任务依赖其他任务,那么可能产生死锁.举个极端的例子,在单线程的Executor中,如果一个任务 ...

  9. Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)

    AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具 ...

随机推荐

  1. MyBatis的关联关系补充 多对多 继承

    多对多 一个学生有多个课程 一个课程有多个学生 思路分析 :使用一个中间表 用学生表和课程表的主键作为中间表的联合主键 1数据库表的设计 课程表 学生表 中间表 2/实体类的设计 课程类 public ...

  2. Android帧动画笔记

    创建drawable资源文件,选择animation-list<?xml version="1.0" encoding="utf-8"?><a ...

  3. 有点难度的JS面试题

    自己总结了一些JS面试题 希望能够帮助正在找工作的程序猿(●´∀`●) 1.js 实现一个函数对javascript中json 对象进行克隆 var oldObject ="sdf" ...

  4. (转)spring学习之@ModelAttribute运用详解

    @ModelAttribute使用详解 1 @ModelAttribute注释方法 例子(1),(2),(3)类似,被@ModelAttribute注释的方法会在此controller每个方法执行前被 ...

  5. AI人工智能-Python实现人机对话

    [前言] AI 在人工智能进展的如火如荼的今天,我们如果不尝试去接触新鲜事物,马上就要被世界淘汰啦~ 本文拟使用Python开发语言实现类似于WIndows平台的“小娜”,或者是IOS下的“Siri” ...

  6. Java并发编程——线程安全及解决机制简介

    简介: 本文主要介绍了Java多线程环境下,可能会出现的问题(线程不安全)以及相应的解决措施.通过本文,你将学习到如下几块知识: 1. 为什么需要多线程(多线程的优势) 1. 多线程带来的问题—线程安 ...

  7. HDU1035 Robot Motion

    Problem Description A robot has been programmed to follow the instructions in its path. Instructions ...

  8. HDU1124 Factorial

    Problem Description The most important part of a GSM network is so called Base Transceiver Station ( ...

  9. Python初识(PyMysql实例)

    为什么学习python呢,好吧,其实我也不知道,反正就是想学习了. 资料什么的全都low了,传值博客免费的就够.不要问我为什么,我基本上都是找的免费的视频.然后传值博客的最多,我真的不是打广告. py ...

  10. python函数(4):递归函数及二分查找算法

    人理解循环,神理解递归!  一.递归的定义 def story(): s = """ 从前有个山,山里有座庙,庙里老和尚讲故事, 讲的什么呢? ""& ...