Thread初探

前言

以前大家写的都是单线程的程序,全是在main函数中调用方法,可以清楚的看到它的效率是特别低的,就像python中使用单线程取爬一个网站,可以说能让你等的吐血,因为数据量实在太大了,今天我们就来看看java的并发编程多线程的学习

创建线程

创建一个线程可以有多种方法,比如继承Thread类,实现Runnable接口......下面我们来详细的看看创建的方法

继承Thread

为什么继承Thread可以直接调用start()方法启动线程呢,因为start()本身就是Thread的方法,也就是继承了Thread的start()方法,因此这个类的对象可以调用start()启动线程

//继承Thread
public class MyThread extends Thread {
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(this.getName()+"正在跑");
}
}
} public class Test{
public static void main(String[] args)
{
Mythread t1=new MyThread(); //创建对象
t1.start(); //启动线程
}
}

注意: 继承Thread类的创建方法一个对象只能创建一个线程,并不能多个线程共用一个对象,只能一个线程对应一个对象,因此我们来看看实现Runnable接口的类来实现多个线程共享同一个对象

实现Runnable接口

//实现Runnable接口
public class Demo implements Runnable {
@Override
public void run() {
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName()+"正在跑");
} }
} //测试类
public class Test{
public static void main(String[] args)
{
Demo d=new Demo(); //创建对象
Thread thread1=new Thread(d); //为对象创建一个线程
Thread thread2=new Thread(d); //创建另外一个线程 //同时启动两个线程
thread1.start();
thread2.start();
}
}

从上面可以清楚的看到实现Runnable接口的类一个对象可以供多个线程共享,并不像继承Thread类只为一个线程使用

简便的创建方法

直接在main方法中创建,如果创建的普通类的对象在外面,那么必须是final修饰,可以实现多个线程同时共享一个对象,这个和实现Runnable接口一样,这时候就要控制同步条件了,如果在run方法中定义对象,那么,就是一个线程对应一个对象,这个就和继承Thread类一样的效果。所以可以根据条件自由选择


//普通的一个类
public class Simple { public void display()
{
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName()+"正在跑");
}
}
} //线程测试类
public class Test {
public static void main(String[] args) { //如果在外面必须使用final,当然也可以直写在run方法中,不过写在外面可以实现多个线程共享一个对象
//写在run方法中当前对象只能为一个线程使用,和继承Thread类一样的效果
final Simple simple=new Simple(); //下面创建使用同一个对象创建同两个线程,实现多个线程共享一个对象,和实现Runnable接口一样的效果
Thread t1=new Thread(){
public void run() {
simple.display();
};
}; Thread t2=new Thread(){
public void run() {
simple.display();
};
}; //启动这两个线程
t1.start();
t2.start();
}}

常用的方法

  • static void sleep(long mils) 使正在运行的线程休眠mils毫秒,但是这里需要注意的是如果线程加了锁,那么使线程休眠并不会释放锁
  • String getName() 得到线程的名称,上面的程序中已经使用了这个方法
  • void setName(String name) 设置正在运行的线程的名字为name
  • start() 启动线程,线程的创建并不意味着线程的启动,只有调用start()方法线程才是真正的开始运行
  • long getId() 返回线程的标识符
  • run() 线程执行的代码都放在run()方法中,在run方法中的调用是有序的,都是按照程序运行的顺序开始执行

使用

下面使用上面的方法创建一个实例


//线程的类,继承Thread
public class MyThread1 extends Thread { public void run() { // 重载run方法,并且在其中写线程执行的代码块
for (int i = 0; i < 10; i++) {
// 获取线程的id和name
System.out.println("Thread-Name: " + this.getName()
+ " Thread-id: " + this.getId());
try {
this.sleep(1000); // 线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
} } } } //线程测试的类
public class Test {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); // 创建线程
t1.setName("第一个线程"); // 设置线程的名字 MyThread1 t2 = new MyThread1();
t2.setName("第二个线程"); t1.start(); // 启动线程,开始运行
t2.start(); }
}
  • void join() 等待该线程终止才能运行其他的线程
  • void join(long mils) 等待该线程的时间为mils毫秒,一旦过了这个时间其他线程正常执行

使用

//线程类
public class MyThread1 extends Thread { public void run() { // 重载run方法,并且在其中写线程执行的代码块
for (int i = 0; i < 10; i++) {
// 获取线程的id和name
System.out.println("Thread-Name: " + this.getName()
+ " Thread-id: " + this.getId());
try {
this.sleep(1000); // 线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
} } } } //测试类
public class Test {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); // 创建线程
t1.setName("第一个线程"); // 设置线程的名字 t1.start(); // 启动线程,开始运行
try {
t1.join(); //阻塞其他线程,只有当这个线程运行完之后才开始运行其他的线程
} catch (InterruptedException e) {
e.printStackTrace();
} for (int i = 0; i < 10; i++) {
System.out.println("主线程正在运行");
} }
} //输出结果 /*
Thread-Name: 第一个线程 Thread-id: 9
Thread-Name: 第一个线程 Thread-id: 9
Thread-Name: 第一个线程 Thread-id: 9
Thread-Name: 第一个线程 Thread-id: 9
Thread-Name: 第一个线程 Thread-id: 9
Thread-Name: 第一个线程 Thread-id: 9
Thread-Name: 第一个线程 Thread-id: 9
Thread-Name: 第一个线程 Thread-id: 9
Thread-Name: 第一个线程 Thread-id: 9
Thread-Name: 第一个线程 Thread-id: 9
主线程正在运行
主线程正在运行
主线程正在运行
主线程正在运行
主线程正在运行
主线程正在运行
主线程正在运行
主线程正在运行
主线程正在运行
主线程正在运行
*/
  • getPriority() 得到当前线程优先级
  • setPriority(int num) 更改线程的优先级(0-10)默认的是5,优先级越高获得cpu资源的几率就会越高

使用

//线程类
public class MyThread1 extends Thread { public void run() { // 重载run方法,并且在其中写线程执行的代码块
for (int i = 0; i < 10; i++) {
// 获取线程的id和name
System.out.println("Thread-Name: " + this.getName()
+ " Thread-id: " + this.getId());
try {
this.sleep(1000); // 线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
} } } } //测试类
public class Test {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); // 创建线程
t1.setName("第一个线程"); // 设置线程的名字 MyThread1 t2 = new MyThread1();
t2.setName("第二个线程"); t2.setPriority(8); //设置第二个线程的优先级为8,第一个线程的优先级为5(是默认的) t1.start();
t2.start(); }
} /*
* 从上面的运行结果可以看出大部分的第二个线程都是在第一个线程之前开始执行的,也就是说优先级越高获得cpu执行的几率就越大
* /
  • setDaemon(boolean) 是否设置为守护线程,如果设置为守护线程,那么主线程销毁守护线程也会随之销毁
  • isDaemon() 判断是否为守护线程

使用

//测试类
public class MyThread1 extends Thread { public void run() { // 重载run方法,并且在其中写线程执行的代码块
for (int i = 0; i < 10; i++) {
// 获取线程的id和name
System.out.println("Thread-Name: " + this.getName()
+ " Thread-id: " + this.getId()); try {
Thread.sleep(1000); //休眠一秒,方便主线程运行结束
} catch (InterruptedException e) {
e.printStackTrace();
} } } } public class Test {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); // 创建线程
t1.setName("第一个线程"); // 设置线程的名字
t1.setDaemon(true);
t1.start(); for (int i = 0; i < 1; i++) {
System.out.println(i);
} }
} //结果:
/*
0
1
2
3
4
5
6
7
8
9
Thread-Name: 第一个线程 Thread-id: 9
*/ /*
* 从上面的结果可以看出,一旦主线程结束,那么守护线程就会自动的结束
* /

参考文章

Thread初探的更多相关文章

  1. Thread线程初探

    using System; using System.Threading; class Example { static void Main() { TimeSpan interval = , , ) ...

  2. .NET文件并发与RabbitMQ(初探RabbitMQ)

    本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址:http://www.cnblogs.com/tdws/p/5860668.html 想必MQ这两个字母对于各位前辈们和老司 ...

  3. NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例

    一.消息队列场景简介 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更复杂,可能包含嵌入对象.消息被发送到队列中,“消息队列”是在消息的传输过程中保存消息的容器 ...

  4. 初探asp.net异步编程之await

    终于毕业了,也顺利进入一家期望的旅游互联网公司.27号入职.放肆了一个多月没写代码,好方啊. 另外一下观点均主要针对于await. 请先看这段话,来自async in C# 5.0.  接下来几个月的 ...

  5. WCF初探-28:WCF中的并发

    理解WCF中的并发机制 在对WCF并发机制进行理解时,必须对WCF初探-27:WCF中的实例化进行理解,因为WCF中的并发特点是伴随着服务实例上下文实现的.WCF的实例上下文模型可以通过Instanc ...

  6. Java Lambda表达式初探

    Java Lambda表达式初探 前言 本文受启发于Trisha Gee在JavaOne 2016的主题演讲Refactoring to Java 8. Java 8已经发行两年多,但很多人仍然在使用 ...

  7. 【转】NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例

    一.消息队列场景简介 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更复杂,可能包含嵌入对象.消息被发送到队列中,“消息队列”是在消息的传输过程中保存消息的容器 ...

  8. WCF初探-11:WCF客户端异步调用服务

    前言: 在上一篇WCF初探-10:WCF客户端调用服务 中,我详细介绍了WCF客户端调用服务的方法,但是,这些操作都是同步进行的.有时我们需要长时间处理应用程序并得到返回结果,但又不想影响程序后面代码 ...

  9. mysql performance_schema 初探

    mysql  performance_schema 初探: mysql 5.5 版本 新增了一个性能优化的引擎: PERFORMANCE_SCHEMA 这个功能默认是关闭的: 需要设置参数: perf ...

随机推荐

  1. Less和Sass的使用

    [Less中的变量] 1.声明变量:@变量名:变量值;  使用变量:@变量名 @length:100px; @color:yellow; @opa:0.5; >>>Less中变量的类 ...

  2. 蓝桥杯-无穷分数-java

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...

  3. seajs的那些坑

    seajs是what? 先看段代码: var loder = {}; var define = loder.define = function(id,deps,factory){ loader[id] ...

  4. 【2017-05-03】winform打印控件、事件对象和事件数据、MDI窗体容器

    一.打印控件 第一步先把打印对象搞出来. - printDocument    打印对象(将要打印的内容放到该对象里,从该对象里取内容打印) 设置他的PrintPage事件(对于要打印的每一页触发一次 ...

  5. Linux系统档案与文件系统的压缩与打包

    以下文章基于centos6.5 文章引自:http://www.jb51.net/LINUXjishu/105916.html 一.Linux下常见的压缩指令 在linux的环境中,压缩文件的扩展名大 ...

  6. Java学习笔记——浅谈数据结构与Java集合框架(第一篇、List)

    横看成岭侧成峰,远近高低各不同.不识庐山真面目,只缘身在此山中. --苏轼 这一块儿学的是云里雾里,咱们先从简单的入手.逐渐的拨开迷雾见太阳.本次先做List集合的三个实现类的学习笔记 List特点: ...

  7. wifi驱动总结(1)

    一.wifi平台设备驱动注册过程Path:Rtw_android.c (rk3399\kernel\drivers\net\wireless\rockchip_wlan\rtl8723au\os_de ...

  8. VR全景智慧城市

    随着虚拟现实产业的发展,我国对虚拟现实产业也越来越重视了.我国虚拟现实VR市场增长速度很快,市场活跃性很高,很多人都看好我国的虚拟现实VR市场,而且未来国内虚拟现实VR市场的销量还将有更大的增长.据赛 ...

  9. 模板不存在:./xx 错误位置 FILE: LINE:110 (thinkphp上传至服务器后模板无法解析原因)

    thinkphp上传至服务器后模板无法解析原因 前几日做好的响应式静态页面上传至虚拟空间,打开网址地址出现: 模板不存在:./App/Admin/View/Config/customerService ...

  10. Java调用IDL方法总结

    Java调用IDL方法总结 Java调用IDL程序,需要先在java中加载IDL的java包(javaidlb.jar),该包不需要下载,在IDL的安装目录中可以直接找到(C:\Program Fil ...