Java给多线程编程提供了内置的支持。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。

这里定义和线程相关的另一个术语—进程:一个进程包括由操作系统分配的内存空间,包含一个或者多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。

多线程能满足程序员编写高效率的程序来达到充分利用CPU的目的。

一个线程的生命周期

线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

下图显示了一个线程完整的生命周期。

对于进程来说,从运行状态转向就绪状态(时间片用完)。

新建状态:

使用new关键字和Thread类及其子类建立一个线程对象后,该对象就处于新建状态。它保持这个状态直到程序start()这个线程。

就绪状态:

当线程对象调用了start()方法之后,该线程就处于就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

运行状态:

如果就绪状态的线程获取CPU资源,就可以执行run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态(完成状态)。

阻塞状态:

如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或者获得设备资源之后可以重新进入就绪状态。可以分为三种:

等待阻塞:运行状态中的线程执行wait()方法,使线程进入到等待阻塞状态。

同步阻塞:线程在获取synchronized同步锁失败(因为同步锁被其他线程占用)。

其他阻塞:通过调用线程的sleep()或者join()发出I/O请求时,线程就会进入到阻塞状态。当sleep()状态超时,join()等待线程终止或者超时,或者I/O处理完毕,线程重新转入就绪状态。

死亡状态:

一个运行状态的线程完成任务或者其他终止条件发生时,该线程就会切换到终止状态。

线程的优先级

每一个Java线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。

Java线程的优先级是一个整数,其取值范围是1(Thread.MIN_PRIORITY)-10(Thread.MAX_PRIORITY)。

默认情况下,每一个线程都会分配一个优先级NORM_PRIORITY(5)。

具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。

创建一个线程

Java提供了三种创建线程的方法:

通过实现Runnable接口;

通过继承Thread类本身;

通过Callable和Future创建线程。

通过实现Runnable接口来创建线程

创建一个线程,最简单的方法是创建一个实现Runnable接口的类。

为了实现Runnable,一个类只需要执行一个方法调用run(),声明如下:

public void run()

你可以重写该方法,重要的是理解run()可以调用其他方法,使用其他类,并声明变量,就像主线程一样。

在创建一个实现Runnable接口的类之后,你可以在类中实例化一个线程对象。

Thread定义了几个构造方法,下面的这个是我们经常使用的:

Thread(Runnable threadOb,String threadName);

这里,threadOb是一个实现Runnable接口的类的实例,并且threadName指定新线程的名字。

新线程创建之后,你调用它的start()方法它才会运行。

void start();

通过继承Thread来创建线程

创建一个线程的第二种方法是创建一个新的类,该类继承Thread类,然后创建一个该类的实例。

继承类必须重写run()方法,该方法是新线程的入口点。它也必须调用start()方法才能执行。

该方法尽管被列为一种多线程实现方式,但是本质上也是实现了Runnable接口的一个实例。

package pkg2020华南虎;

class ThreadDemo extends Thread {

private Thread t;

private String threadName;

ThreadDemo(String name) {

threadName = name;

System.out.println("Creating " + threadName);

}

public void run() {

System.out.println("Running " + threadName);

try {

for (int i = 4; i > 0; i--) {

System.out.println("Thread: " + threadName + ", " + i);

// 让线程睡眠一会

Thread.sleep(50);

}

} catch (InterruptedException e) {

System.out.println("Thread " + threadName + " interrupted.");

}

System.out.println("Thread " + threadName + " exiting.");

}

public void start() {

System.out.println("Starting " + threadName);

if (t == null) {

t = new Thread(this, threadName);

t.start();

}

}

}

public class TestThread {

public static void main(String args[]) {

ThreadDemo T1 = new ThreadDemo("Thread-1");

T1.start();

ThreadDemo T2 = new ThreadDemo("Thread-2");

T2.start();

}

}

Thread方法

下表列出了Thread类的一些重要方法:

测试线程是否处于活动状态。上述方法是被Thread对象调用的。下面的方法是Thread类的静态方法。

实例

如下的ThreadClassDemo程序演示了Thread类的一些方法:

package pkg2020华南虎;

/**

*

* @author yl

*/

public class DisplayMessage implements Runnable {

private String message;

public DisplayMessage(String message) {

this.message = message;

}

public void run() {

while (true) {

System.out.println(message);

}

}

}

package pkg2020华南虎;

/**

*

* @author yl

*/

public class GuessANumber extends Thread {

private int number;

public GuessANumber(int number) {

this.number = number;

}

public void run() {

int counter = 0;

int guess = 0;

do {

guess = (int) (Math.random() * 100 + 1);

System.out.println(this.getName() + "guess " + guess);

counter++;

} while (guess != number);

System.out.println("** Correct!" + this.getName() + "in" + counter + "guess.***");

}

}

package pkg2020华南虎;

/**

*

* @author yl

*/

public class ThreadClassDemo {

public static void main(String[] args) {

Runnable hello = new DisplayMessage("Hello");

Thread thread1 = new Thread(hello);

thread1.setDaemon(true);

thread1.setName("hello");

System.out.println("Starting hello thread...");

thread1.start();

Runnable bye = new DisplayMessage("Goodbye");

Thread thread2 = new Thread(bye);

thread2.setPriority(Thread.MIN_PRIORITY);

thread2.setDaemon(true);

System.out.println("Starting goodbye thread...");

thread2.start();

System.out.println("Starting thread3...");

Thread thread3 = new GuessANumber(27);

thread3.start();

try {

thread3.join();

} catch (InterruptedException e) {

System.out.println("Thread interrupted.");

}

System.out.println("Starting thread4...");

Thread thread4 = new GuessANumber(75);

thread4.start();

System.out.println("main() id ending...");

}

}

通过Callable和Future创建线程

创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。

创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

使用FutureTask对象作为Thread对象的target创建并启动新线程。

调用FutrueTask对象的get()方法来获得子线程执行结束后的返回值。

package pkg2020华南虎;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.FutureTask;

public class CallableThreadTest implements Callable {

public static void main(String[] args) {

CallableThreadTest ctt = new CallableThreadTest();

FutureTask ft = new FutureTask<>(ctt);

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

System.out.println(Thread.currentThread().getName() + " 的循环变量i的值" + i);

if (i == 20) {

new Thread(ft, "有返回值的线程").start();

}

}

try {

System.out.println("子线程的返回值:" + ft.get());

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

@Override

public Integer call() throws Exception {

int i = 0;

for (; i < 100; i++) {

System.out.println(Thread.currentThread().getName() + " " + i);

}

return i;

}

}

创建线程的三种方式的对比

采用实现Runnable、Callable接口的方式创建多线程时,线程类只是实现了Runnable接口或者Callable接口,还可以继承其他类。

使用继承Thread类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。

线程的几个主要概念

线程同步

线程间通信

线程死锁

线程控制:挂起、停止和恢复

多线程的使用

有效利用多线程的关键是理解程序是并发执行而不是串行执行的,例如:程序中有两个子程序需要并发执行,这时候就需要利用多线程编程。

通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。

请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU花费在上下文的切换的时间将多于执行程序的时间。

多线程编程java_Java多线程编程相关推荐

  1. 多线程编程 java_java多线程编程

    一.多线程的优缺点 多线程的优点: 1)资源利用率更好 2)程序设计在某些情况下更简单 3)程序响应更快 多线程的代价: 1)设计更复杂 虽然有一些多线程应用程序比单线程的应用程序要简单,但其他的一般 ...

  2. 多线程共享java_java多线程之共享资源

    转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/42587821 作者:小马 先看一个示例, 多个计数器线程实例(TwoCounter ...

  3. python多线程没有java_Java 多线程启动为什么调用 start() 方法而不是 run() 方法?...

    多线程在工作中多多少少会用到,我们知道启动多线程调用的是 start() 方法,而不是 run() 方法,你知道原因吗? 在探讨这个问题之前,我们先来了解一些多线程的基础知识~ 线程的状态 Java ...

  4. 面向串口编程java_Java串口编程例子

    最近笔者接触到串口编程,网上搜了些资料,顺便整理一下.网上都在推荐使用Java RXTX开源类库,它提供了Windows.Linux等不同操作系统下的串口和并口通信实现,遵循GNU LGPL协议.看起 ...

  5. 猴子爬山编程java_Java趣味编程100例

    第1章 变幻多姿的图表(教学视频:69分钟) 1.1 金字塔图案 1.2 九九乘法表 1.3 余弦曲线 1.4 奥运五环旗 1.5 杨辉三角 1.6 国际象棋棋盘 1.7 心形图 1.8 回型矩阵 1 ...

  6. 异步委托实现多线程winform控件编程

            private void button1_Click(object sender, EventArgs e)         {             ThreadStart ts  ...

  7. gil php,网络编程之多线程——GIL全局解释器锁

    网络编程之多线程--GIL全局解释器锁 一.引子 定义: In CPython, the global interpreter lock, or GIL, is a mutex that preven ...

  8. PHP 高级编程之多线程

    PHP 高级编程之多线程 http://netkiller.github.io/journal/thread.php.html Mr. Neo Chen (netkiller), 陈景峰(BG7NYT ...

  9. iOS多线程拾贝------操作巨人编程

    iOS多线程拾贝------操作巨人编程 多线程 基本 实现方案:pthread - NSThread - GCD - NSOperation Pthread 多平台,可移植 c语言,要程序员管理生命 ...

最新文章

  1. spring入门(12)-spring与hibernate整合完成增删改查的操作(继承HibernateDaoSupport调用hibernateTemplate类)
  2. 加快发展设施业 农业大健康-林裕豪:从玉农业践行基础支撑
  3. 电脑装服务器系统好处,服务器选用Linux系统的几个好处
  4. 计算机网络之数据链路层:11、CSMA/CD协议-随机访问介质访问控制
  5. 仿真器和模拟器的区别是什么?
  6. 新发现的两个Delphi要点。
  7. qt 将相应字符写入txt文件
  8. git merge 和 git rebase 小结
  9. 静态文件用什么服务器配置,静态文件服务器路径怎么配置好
  10. datetime只要年月python_Python 的日期和时间处理
  11. 【图像处理】基于matlab GUI打靶仿真系统【含Matlab源码 1043期】
  12. SPSS常用方法及操作
  13. JavaScript零基础入门 11:JavaScript实现图片上传并预览
  14. ||分享一些百度云下载不限速神器||
  15. Scratch少儿编程
  16. windows 10 微软拼音输入法设置
  17. 行列式java_n阶行列式的全排列求解(Java)
  18. Python3之数据结构
  19. B站视频下载工具唧唧down的安装和使用教程
  20. 洞悉旅居新市场,木莲庄酒店集团开拓酒店多元新玩法

热门文章

  1. 当薪资倒挂成为常态,然后呢?
  2. 关于赠书《VS Code》断货延迟的通知!
  3. Mybatis 强大的结果映射器ResultMap
  4. 深度学习手势识别带你玩转神庙逃亡
  5. java solar_java中的内部类总结
  6. python DBSCAN聚类例子
  7. yolov5 ncnn
  8. python条码识别
  9. pip 查看安装路径
  10. asio::write RuntimeError