当前位置: 首页 > 编程日记 > 正文

20180829-Java多线程编程


Java 多线程编程

Java给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。

程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径。

多线程是多任务的一种特别的形式。多线程比多任务需要更小的开销。

这里定义和线程相关的另一个术语:

进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。
一个线程不能独立的存在,它必须是进程的一部分。
一个进程一直运行,直到所有的非守候线程都结束运行后才能结束。

多线程能满足程序员编写非常有效率的程序来达到充分利用CPU的目的,因为CPU的空闲时间能够保持在最低限度。


一个线程的生命周期

线程经过其生命周期的各个阶段。

新状态: 一个新产生的线程从新状态开始了它的生命周期。它保持这个状态知道(直到)程序start这个线程。

运行状态:当一个新状态的线程被start以后,线程就变成可运行状态,一个线程在此状态下被认为是开始执行其任务

就绪状态:当一个线程等待另外一个线程执行一个任务的时候,该线程就进入就绪状态。
当另一个线程给就绪状态的线程发送信号时,该线程才重新切换到运行状态。

休眠状态: 由于一个线程的时间片用完了,该线程从运行状态进入休眠状态。
当时间间隔到期或者等待的时间发生了,该状态的线程切换到运行状态。

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

线程的优先级

每一个Java线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。
Java优先级在MIN_PRIORITY(1)和MAX_PRIORITY(10)之间的范围内。默认情况下,每一个线程都会分配一个优先级NORM_PRIORITY(5)。

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

创建一个线程


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

通过实现Runable接口;
通过继承Thread类本身。


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

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

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

public void run()

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

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

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

Thread(Runnable threadOb,String threadName);

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

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

void start();

下面是一个创建线程并开始让它执行的实例:


// 创建一个新的线程

class NewThread implements Runnable{

Thread t;
NewThread(){
//创建第二个新线程

t = new Thread(this,"Demo Thread");
System.out.println("Child thread:" + t);
t.start(); //开始线程

}

// 第二个线程入口

public void run(){
try{

for(int i=5;i>0;i--){
System.out.println("Child Thread:" + i);
//暂停线程
Thread.sleep(50);
}

}catch(InterruptedException e){
System.out.println("Child interrupted");
}

System.out.println("Exiting child thread");
}
}

public class ThreadDemo{

public static void main(String args[]){
new NewThread(); //创建一个新线程

try{
for(int i = 5;i>0;i--){
System.out.println("Main Thread:" + i);
Thread.sleep(100);
}
}catch(InterruptedException e){
System.out.println("Main thread interrupted");
}
System.out.println("Main thread exiting.");
}

}


编译以上程序运行结果如下:

Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.

通过继承Thread来创建线程

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

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

// 通过继承 Thread 创建线程
class NewThread extends Thread {
NewThread() {
// 创建第二个新线程
super("Demo Thread");
System.out.println("Child thread: " + this);
start(); // 开始线程
}

// 第二个线程入口
public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
// 让线程休眠一会
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}


public class ExtendThread {
public static void main(String args[]) {
new NewThread(); // 创建一个新线程
try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}

Thread 方法

Thread类的一些重要方法:


public void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。


public void run()
如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。

public final void setName(String name)
改变线程名称,使之与参数 name 相同。


public final void setPriority(int priority)
更改线程的优先级。


public final void setDaemon(boolean on)
将该线程标记为守护线程或用户线程。


public final void join(long millisec)
等待该线程终止的时间最长为 millis 毫秒。


public void interrupt()
中断线程。


public final boolean isAlive()
测试线程是否处于活动状态。

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


public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。


public static void sleep(long millisec)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

public static boolean holdsLock(Object x)
当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。

public static Thread currentThread()
返回对当前正在执行的线程对象的引用。


public static void dumpStack()
将当前线程的堆栈跟踪打印至标准错误流。


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


// 文件名 : DisplayMessage.java
// 通过实现 Runnable 接口创建线程
public class DisplayMessage implements Runnable
{
private String message;
public DisplayMessage(String message)
{
this.message = message;
}
public void run()
{
while(true)
{
System.out.println(message);
}
}
}


// 文件名 : GuessANumber.java
// 通过继承 Thread 类创建线程

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()
+ " guesses " + guess);
counter++;
}while(guess != number);
System.out.println("** Correct! " + this.getName()
+ " in " + counter + " guesses.**");
}
}

// 文件名 : ThreadClassDemo.java
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(hello);
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() is ending...");
}
}

运行结果如下,每一次运行的结果都不一样。

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Thread-2 guesses 27
Hello
** Correct! Thread-2 in 102 guesses.**
Hello
Starting thread4...
Hello
Hello
..........remaining result produced.

线程的几个主要概念:


在多线程编程时,你需要了解以下几个概念:

线程同步
线程间通信
线程死锁
线程控制:挂起、停止和恢复

多线程的使用

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


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


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

转载于:https://www.cnblogs.com/Alanf/p/9556271.html

相关文章:

b-blkid查看磁盘设备文件系统类型

blkid命令对查询设备上所采用文件系统类型进行查询。blkid主要用来对系统的块设备(包括交换分区)所使用的文件系统类型、LABEL、UUID等信息进行查询 改命令存在于util-linux-2.23.2-26.el7.x86_64软件包之中 常用命令展示 blkid查询所有设备的文件系统…

与后台交互方法一 ——Ajax

一、Ajax:为无刷新读取服务器端数据,常用在用户注册、在线聊天室等。 使用Ajax读取数据时有以下几点需要注意: 1.字符集编码前后台要一致,否则前台显示的数据为乱码。 2.使用随机数或时间清除缓存、阻止缓存,防止服务器…

php复选框关联数据库字段,通过php将复选框中的多个值插入数据库

|我想将此表单值插入到datanase中:Brand 1Brand 2Brand 3Brand 4Brand 5这些文本框是通过php从数据库中的表中获取的,并且可能是Variable我想以这种格式插入数据库如果检查品牌1,则$ brand \“ 1,\”;最后像这样:inse…

WPF中的容器控件——Grid

网格布局 123123123123123123123123123123123123123123123123123123123123123123123123123123112312312312312312312312312312312312312312312312312312312312312312 123123实际应用中应该少不了网格布局,grid布局的特点: 1.每个grid中可以放多个控件&am…

h-hdparm打开关闭磁盘cache

查看磁盘型号 hdparm -I /dev/sde 查看磁盘缓存情况 hdparm -W /dev/sdb 打开或者关闭磁盘cache hdparm -W 0 /dev/sdb关闭 hdparm -W 1 /dev/sdb打开

linux diff 补丁文件夹,LINUX下制作补丁文件 diff,patch

diff(differential)功能说明:比较文件的差异。语  法:diff [-abBcdefHilnNpPqrstTuvwy][-;][-C ;][-D ;][-I ;][-S ;][-W ;][-x ;][-X ;][--help][--left-column][--suppress-common-line][文件或目录1][文件或目录2]补充说明:diff以逐行的…

连通性2 无向图的双连通 bcc

待续。。。转载于:https://www.cnblogs.com/assult/p/3312457.html

网络规划设计培训与方案集下载

http://down.51cto.com/data/96887为OSPF城域网部署专题http://down.51cto.com/data/565799华为、H3C、神码等的一些关于网络规划设计的PPT资料,有技术性的,有理论的,有技术理论的。http://down.51cto.com/data/96885策略路由与路由策略原理培…

C语言标准库之strcat函数

2018-10-20C库函数strcat()函数的功能是实现字符串的拼接。其函数原型如下所示char *strcat(char *dest, const char *src) 1、参数说明 dest:指向目标数组,该目标包含看一个C字符串,且足够容纳追加之后的字符串。 src: 指向要追加的字…

设计模式——单例模式(Singleton)

保证一个类仅有一个实例,并提供一个访问它的全局访问点。——DP UML类图 模式说明 个人认为单例模式是所有设计模式中最为简单的一个模式,因为实现这个模式仅需一个类,而不像其他模式需要若干个类。这个模式中,需要注意的一点就是…

l-logger命令基本介绍

logger是一个shell命令接口,可以通过该接口使用Syslog的系统日志模块,还可以从命令行直接向系统日志文件写入一行信息 logger语法: 可以使用的相关命令 -d, --udp 使用数据报(UDP)而不是使用默认的流连接(TCP) -i, --id 逐行记录每一次logger的进程…

红旗linux可以做服务器吗,在红旗Linux中的E-MAIL服务器(postfix及dovecot)配置过程...

在红旗Linux中打开一个系统终端,使用纯文本方式配置邮件服务器:1、进入postfix服务(smtp服务,用来发送服务)配置文件目录:输入如下命令:cd /etc/postfix2、使用邮件服务器的模板配置文件main.cf.default覆盖原配置文件…

Spring Filter过滤器,Spring拦截未登录用户权限限制

实现的功能:判断用户是否已登录,未登录用户禁止访问任何页面或action,自动跳转到登录页面。 比较好的做法是不管什么人都不能直接访问jsp页面,要访问就通过action,这样就变成了一个实实在在的权限控制了。 那么就有3种…

NOIP模拟 蛋糕(DP+Dilworth定理)

QAQ 【题目分析】 谁能告诉我为什么我的网络流炸了吗。。。。。。。。(我相信是SPJ的锅这年头暴力不好打啊) 所以我们按x排序,然后就是要找到序列中严格上升序列的最少个数,然后。。。。duang。。。。Dilworth定理(上升…

l-lsblk查看设备可用块设备

lsblk命令(列出块设备)用于列出所有可用的块设备的信息,但是, 它并没有列出有关的RAM磁盘的信息。块设备的例子是硬盘,闪存驱动器,CD-ROM等等,一般可以和blkid命令搭配,blkid可以查看更详细的磁盘信息&…

hdu 4720

最小覆盖圆的模板&#xff1b; 1 #include<stdio.h>2 #include<string.h>3 #include<math.h>4 struct Point5 {6 double x;7 double y;8 } pt[1005];9 struct Traingle10 {11 struct Point p[3];12 };13 struct Circle14 {15 struct Point c…

opencv可以在linux上运行,linux上 安装并 运行opencv

我是在树莓派上安装的。1.先安装依赖项OpenCV 2.2以后版本需要使用Cmake生成makefile文件&#xff0c;因此需要先安装cmake。sudo apt-get install build-essentialsudo apt-get install cmakesudo apt-get install libgtk2.0-devsudo apt-get install pkg-configsudo apt-get …

Calendar类点点滴滴积累

为什么80%的码农都做不了架构师&#xff1f;>>> set(f, value) 将日历字段 f 更改为 value。此外&#xff0c;它设置了一个内部成员变量&#xff0c;以指示日历字段 f 已经被更改。尽管日历字段 f 是立即更改的&#xff0c;但是直到下次调用 get()、getTime()、get…

3.3 栈的链式存储结构

<?php header("content-type:text/html;charsetutf-8"); /*** 栈的链式存储结构的基本操作**包括* 1.初始化 __contruct()* 2.进栈操作 push()* 3.出栈操作 pop()* 4.销毁栈 destroyStack()* 5.清空栈 clearStack()* 6.遍历栈 stackTraverse()*/ class Node{publ…

readelf 读取动态链接表命令

readelf -sV xxx 查看指定二进制文件运行时的加载库以及对应版本 并依据该命令可以修改某一二进制文件依赖的glibc库函数的版本&#xff0c;从而让改二进制程序可以运行在低版本的操作系统 readelf 读取链接表头 readelf -h xxx ELF文件介绍 ELF&#xff08;executable and …

[转]cocos2d-x

Cocos2d-x 是一个支持多平台的 2D 手机游戏引擎&#xff0c;使用 C 开发&#xff0c;基于OpenGL ES&#xff0c;基于Cocos2d-iphone&#xff0c;支持 WOPhone, iOS 4.1, Android 2.1 及更高版本, WindowsXP & Windows7&#xff0c;WindowsPhone 8.[1]Cocos2d-x是一个开源的…

Linux哪个和Windows很像,Linuxfx - 这套Linux操作系统看起来和Windows 10非常类似

正如你在截图中所看到的那样&#xff0c;Linuxfx的外观和感觉与Windows 10非常类似&#xff0c;甚至还可以得到一个带有Windows开始按钮的开始菜单&#xff0c;然而&#xff0c;这个实际上可能是一个问题&#xff0c;因为微软可能不喜欢在另一个操作系统中看到它的Windows标志。…

OSPF工作原理

ospf工作原理链路状态路由协议open标准最短路径优先&#xff08;spf&#xff09;算法链路状态路由协议&#xff08;vs&#xff0c;距离矢量&#xff09;与rip的区别 rip是周期性更新&#xff08;30&#xff09;ospf 不发送完整的路由条目但是它发送链路状态的更新有不同的分…

第十八章 MySQL Workbench5.2使用(待续)

转载于:https://www.cnblogs.com/hzzjj/p/9826074.html

r-rpm常用命令集

rpm 安装rpm包 rpm -ivh xxx.rpm rpm -ivh --nodeps --force xxx.rpm强行安装&#xff0c;不考虑依赖性 rpm --nodeps --force -Uvh *同样强行安装&#xff0c;不考虑依赖性 查看一个文件夹属于那个rpm包 rpm -qf /path/filename 查看文件属于哪个rpm包 rpm -qf xxx.so …

MySQL-存储过程

我们常用的操作数据库语言SQL语句在执行的时候需要要先编译, 然后执行; 而存储过程&#xff08;Stored Procedure&#xff09;是一组为了完成特定功能的SQL语句集, 经编译后存储在数据库中, 用户通过指定存储过程的名字并给定参数&#xff08;如果该存储过程带有参数&#xff0…

查看linux虚拟机信息,虚拟机:Linux查看线程信息的步骤

1. 使用 pstree -p PIDps aux | grep firefox | grep -v grepcharles 26058 0.0 0.0 4908 1152 &#xff1f; S 19:17 0:00 /bin/sh /usr/lib/firefox-3.5.4/run-mozilla.sh /usr/lib/firefox-3.5.4/firefoxcharles 26073 7.6 3.4 284264 70164 &#xff1f; Sl 19:17 4:36 /us…

下载备忘:甘特图实现的代码

通过asp.net 代码&#xff0c;拼接字符串&#xff0c;实现甘特图。 样式和原型全部来源于jquery.ganttView插件&#xff0c; https://github.com/mbielanczuk/jQuery.Gantt 通过修改该代码&#xff0c;实现了可以调节高度&#xff0c;宽度等多种参数&#xff0c;具体看代码即可…

Spyder更改默认工作路径已经文件路径

打开spyder&#xff0c;选择菜单栏中的Tools--->Preferences--->Current working directory 然后选择最下面的单选按钮The following directory 。具体操作如下所示 更改文件存放路径 直接点击右上角的的文件夹图标 选择合适的路径即可&#xff1a; 希望能帮到你 转载…

mysql字段类型

数字类型 列类型 需要的存储量 范围、备注 TINYINT 1 个字节 一个很小的整数 有符号的范围是-128到127&#xff0c;无符号的范围是0到255 SMALLINT 2 个字节 一个比较小的整数 有符号的范围是-32768到32767&#xff0c;无符号的范围是0到65535 MEDIUMINT 3 个字节 一…