java基础24 线程、多线程及线程的生命周期(Thread)
1.1、进程
正在执行的程序称作为一个进程.进程负责了内存空间的划分
疑问1:windows电脑称之为多任务的操作系统,那么Windows是同时运行多个应用程序呢?
从宏观的角度:windows确实在同时运行多个程序.
从微观的角度:cpu是做一个快速的切换执行的动作,速度太快,所以你感觉不到切换而已.
1.2、线程
线程在一个进程中负责了代码的执行,进程中的一个执行路径
1.3、多线程
在一个进程中有多个线程同时在执行不同的任务
疑问2:线程负责了代码的执行,我们之前没有学过线程,为什么代码可以执行?
任何一个java程序,在jvm运行时都会创建一个main线程执行main方法中的所有代码.
1.4、多线程好处
1.解决一个进程中能执行多个任务的问题.
2.提高了资源的利用率
1.5、多线程弊端
1.增加了cpu的负担
2.降低了一个进程中的线程执行的概率
3.引发了线程安全问题
4.出现死锁的现象
1.6、创建多线程的方式
方式一:
1.自定义一个类继承Thread类
2.重写Thread的类里面的run方法,自定义线程的代码写在run方法里面
3.创建Thread的子类对象,并且调用start方法开启线程.
注意:一个线程一旦开启,那么这个线程就会执行run方法中的代码,run方法千万不要直接调用,如果直接调用它就相当于一个普通方法,就不会开启新的线程。
疑问3: 重写run方法的目的是什么?
每个线程都有自己的任务代码,jvm创建主线程的任务代码就是main方法中的所有代码,自定义线程的任务代码,需要写在run方法里面,自定线程负责run方法中的代码
方式二:
1.自定义一个类实现Runnable接口
2.实现Runnable里面的run方法,把自定义线程的任务定义在run方法里面
3.创建Runnable实现类对象
4.创建Thread对象,并且把Runnable实现类对象作为参数传递
5.调用Thread对象的start方法开启一个线程
推荐使用:第二种 实现Runnable接口的方式;因为java单继承,多实现
问题4:请问Runnable实现对象是线程对象吗?
答:Runnable实现类对象并不是一个线程对象,只不过实现了Runnable接口的对象而已,只有Thread或者Thread的子类才是线程对象
问题5:为啥要把Runnable实现类对象作为参数传递给Thread对象呢?作用是什么?
答:作用就是把Runnable实现类对象的run方法作为线程的任务代码去执行了.
1.7、实例
package com.zn.thread; /**
* @author DSHORE / 2018-5-3
* 方式1的实例
*/
/*创建多线程的方式
* 方式一:
* 1.自定义一个类继承Thread类
* 2.重写Thread的类里面的run方法,自定义线程的代码写在run方法里面
* 3.创建Thread的子类对象,并且调用start方法开启线程.
*
* 注意:一个线程一旦开启,那么这个线程就会执行run方法中的代码,run方法千万不要直接调用,如果直接调用它就相当于一个普通方法,就不会开启新的线程.
*
* */
public class Demo1 extends Thread {//1.自定义一个类继承Thread类
@Override
public void run() {//2.重写Thread的类里面的run方法,自定义线程的代码写在run方法里面
for(int i=;i<;i++){
System.out.println("自定义线程"+i);
}
}
public static void main(String[] args) {
Demo1 d=new Demo1();//3.创建Thread的子类对象,并且调用start方法开启线程.
d.start(); for(int i=;i<;i++){
System.out.println("主线程"+i);
}
}
}
运行结果图: 注:每次的运行结果都不一样,线程问题
package com.zn.thread; /**
* @author DSHORE / 2018-5-3
* 方式2的实例
*/
/*方式二:
* 1.自定义一个类实现Runnable接口
* 2.实现Runnable里面的run方法,把自定义线程的任务定义在run方法里面
* 3.创建Runnable实现类对象
* 4.创建Thread对象,并且把Runnable实现类对象作为参数传递
* 5.调用Thread对象的start方法开启一个线程
*
* 推荐使用:第二种 实现Runnable接口的方式;因为java单继承,多实现
*/
class Test implements Runnable{ @Override
public void run() { for(int i=;i<;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
public class Demo2 { public static void main(String[] args) {
//创建Runnable实现类对象
Test t=new Test();
//创建Thread对象,并且把Runnable实现类对象作为参数传递
Thread d=new Thread(t,"二狗子");
//调用Thread对象的start方法开启一个线程
d.start();
for (int i = ; i <; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
运行结果图
1.8、线程的生命周期 图解
线程生命周期的五种状态:
1、新建(new Thread):当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值
2、就绪(runnable):当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行
3、运行(running):如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态
4、堵塞(blocked):当处于运行状态的线程失去所占用资源之后(正在运行的线程让出CPU并暂停自己的执行),便进入阻塞状态
5、死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
线程生命周期详解:https://www.cnblogs.com/sunddenly/p/4106562.html 或 https://blog.csdn.net/pange1991/article/details/53860651
下面是:wait()、notify()、notifyAll()、interrupt()、setDaemon()、join() 等方法的使用
package com.zn.thread; /*
* 线程的通讯:一个线程完成了自己的任务时,要通知另一个线程去完成另一个任务
*
* 生产者与消费者
*
* wait():等待。如果线程执行到了wait方法,那么该线程会进入等待状态,等待状态下的线程必须要被其他线程调用notify()方法才能唤醒.
* notify():唤醒。唤醒线程池等待的其中一条线程
* notifyAll(): 唤醒线程池中所等待的线程
* */
//产品
class Product{
String name;//产品名字
double price;//价格
boolean flag=false;//生产者是否生产完成的标志,默认是没有生产完成
}
//生产者
class Producer extends Thread{
Product p;
public Producer(Product p) {
this.p=p;
}
@Override
public void run() {
int i=;
while(true){
synchronized (p) {
if(p.flag==false){
if(i%==){
p.name="苹果";
p.price=5.0;
}else{
p.name="香蕉";
p.price=3.5;
}
System.out.println("生存者生产出了:"+p.name+"; 价格是:"+p.price);
p.flag=true;//flag为true时,通知消费者去消费
i++;
p.notify();//唤醒 消费者去消费
}else{
try {
p.wait();//生产者等待
} catch (InterruptedException e) {
e.printStackTrace();//打印异常信息
}
}
}
}
}
}
//消费者
class Customer extends Thread{
Product p;
public Customer(Product p) {
this.p=p;
}
@Override
public void run() {
while(true){
synchronized (p) {
if(p.flag==true){
System.out.println("消费者消费了:"+p.name+"; 价格:"+p.price);
p.flag=false;//flag为false时,通知生产者去生产
p.notify();//唤醒 生产者去生产
}else{
try {
p.wait();//消费者也等待了
} catch (InterruptedException e) {
e.printStackTrace();//打印异常信息
}
}
}
}
}
}
public class Demo5 {
public static void main(String[] args) {
Product p=new Product();
//创建线程对象
Producer producer=new Producer(p);
Customer customer=new Customer(p);
//开启线程
producer.start();
customer.start();
}
}
package com.zn.thread;
/*停止线程:
* 1.停止一个线程 我们一般都会通过一个变量去控制
* 2.如果需要停止一个处于等待状态的线程,那么我们需要通过变量配合notify方法或者interrupt()来使用
* */
public class Demo2 extends Thread{
boolean flag=true;
public Demo2(String name) {
super(name);
}
@Override
public synchronized void run() {
int i=;
while(flag){
System.out.println("嘿,你好"+Thread.currentThread().getName()+":"+i);
i++;
}
}
public static void main(String[] args) {
Demo2 d=new Demo2("狗娃");
d.start();
System.out.println("");
for (int i = ; i <; i++) {
d.flag=false;
d.interrupt(); //interrupt():调用该方法后,该线程被置于"中断状态"
}
}
}
package com.zn.thread;
/*
* 保护线程(后台线程):在一个进程中如果只剩下了守护线程,那么守护线程也会死亡
* 需求:模拟QQ下载更新包
*
* */
public class Demo3 extends Thread{
public Demo3(String name){
super(name);
}
@Override
public void run() {
for (int i = ; i <=; i++) {
System.out.println("更新包目前下载"+i+"%");
if(i==){
System.out.println("下载完毕");
}
}
try {
Thread.sleep();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
Demo3 d=new Demo3("后台线程");
d.setDaemon(true);//将该线程标记为守护线程或用户线程,该方法必须在启动线程前调用
System.out.println(d.isDaemon());
d.start();
for (int i = ; i <=; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
join() 方法
package com.zn.thread; /**
* @author DSHORE / 2018-5-14
*
*/
/*
* join()方法:加入
*
* 需求:在没加油处插入去买酱油的过程,顺序要正确
*
* */ //老妈
class Mon extends Thread{
@Override
public void run() {
System.out.println("妈妈洗菜");
System.out.println("妈妈切菜");
System.out.println("妈妈准备炒菜,发现没酱油了");
Son s=new Son();
s.start();
try {
s.join();//加入,一个线程如果执行join语句,那么就会有新的线程加入,执行该语句的线程必须要让步给新加入的线程完成任务,然后才能继续执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("妈妈继续炒菜");
System.out.println("全家一起卡饭...");
}
}
//儿子
class Son extends Thread{
@Override
public void run() {
System.out.println("让儿子下楼去买");
System.out.println("儿子买完酱油");
System.out.println("上楼把酱油给老妈");
}
}
public class Demo8 {
public static void main(String[] args) {
Mon m=new Mon();
m.start();
}
}
运行结果图
原创作者:DSHORE 作者主页:http://www.cnblogs.com/dshore123/ 原文出自:http://www.cnblogs.com/dshore123/p/8984060.html 欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!) |
java基础24 线程、多线程及线程的生命周期(Thread)的更多相关文章
- Java基础加强之多线程篇(线程创建与终止、互斥、通信、本地变量)
线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...
- JAVA基础知识之多线程——控制线程
join线程 在某个线程中调用其他线程的join()方法,就会使当前线程进入阻塞状态,直到被join线程执行完为止.join方法类似于wait, 通常会在主线程中调用别的线程的join方法,这样可以保 ...
- Java基础知识(多线程和线程池)
新建状态: 一个新产生的线程从新状态开始了它的生命周期.它保持这个状态直到程序 start 这个线程. 运行状态:当一个新状态的线程被 start 以后,线程就变成可运行状态,一个线程在此状态下被认为 ...
- Java基础教程:多线程基础(2)——线程间的通信
Java基础教程:多线程基础(2)——线程间的通信 使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控与监督. 线程间的通信 ...
- Java基础教程:多线程基础——线程池
Java基础教程:多线程基础——线程池 线程池 在正常负载的情况瞎,通过为每一个请求创建一个新的线程来提供服务,从而实现更高的响应性. new Thread(runnable).start() 在生产 ...
- Java基础图解,JVM,线程,Spring,TCP,SpringMVC等开发体系图解
Java基础图解,JVM,线程,Spring,TCP,SpringMVC等开发体系图解 1.Java虚拟机运行时数据区图 2. 堆的默认分配图 3.方法区结构图 4.对象的内存布局图 5.对象头的Ma ...
- Java基础教程:多线程基础(1)——基础操作
Java:多线程基础(1) 实现多线程的两种方式 1.继承Thread类 public class myThread extends Thread { /** * 继承Thread类,重写RUN方法. ...
- Java基础教程:多线程基础(4)——Lock的使用
Java基础教程:多线程基础(4)——Lock的使用 快速开始 Java 5中Lock对象的也能实现同步的效果,而且在使用上更加方便. 本节重点的2个知识点是:ReentrantLock类的使用和Re ...
- Java基础教程:多线程杂谈——双重检查锁与Volatile
Java基础教程:多线程杂谈——双重检查锁与Volatile 双重检查锁 有时候可能需要推迟一些高开销的对象初始化操作,并且只有在使用这些对象时才进行初始化.此时程序员可能会采用延迟初始化.但要正确实 ...
- Java基础教程:多线程基础(5)——倒计时器(CountDownLatch)
Java基础教程:多线程基础(5)——倒计时器(CountDownLatch) 引入倒计时器 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种 ...
随机推荐
- 【codeforces 553E】 Kyoya and Train
http://codeforces.com/problemset/problem/553/E (题目链接) 艹尼玛,CF还卡劳资常数w(゚Д゚)w!!系统complex被卡TLE了T_T,劳资写了一天 ...
- 《Linux内核分析》期末总结及学习心得
[洪韶武 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ] 一.学习心得 本学 ...
- 【agc019C】Fountain Walk
Portal --> agc019C Description 有一个\(10^8*10^8\)的网格图,一格距离为\(100\),第\(x\)条竖线和第\(y\)条横线的交点记为\((x,y)\ ...
- redis sentinel集群
ip分布情况: sentinel-1/redis 主 10.11.11.5 sentinel-2/redis 从 10.11.11.7 sentinel-3/redis 从 10.11.11.8 ha ...
- 防止jquery ajax 重复提交
var requestSent = false; jQuery("#buttonID").click(function() { if(!requestSent) { request ...
- windows查找端口占用/ 终结端口占用 ------------windows小技巧
前沿 我是一名小程序员,经常通过一些类似tomcat,jettry 等服务器工具 调试项目.有时候莫名其妙的就会出现 程序关闭不正常的情况!去查端口又死活找不到!最后只能重启电脑 后面,在网上查了一些 ...
- MyEclipse和Eclipse中jsp、html格式化自动排版问题
一.myeclipse的漂亮排版设置 步骤: 在左侧快捷 “搜索” 框里面输入 html . 点击选中左侧HTML Source . line - width 是设置当前行里面有多少字符时,就换行.这 ...
- CSS3实战-文字篇
text-shadow的大作用 多颜色阴影效果,用逗号分隔text-shaodow即可. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tr ...
- CPU字节序
小端存储:低对低,高对高(低位存储在低地址,高位存储在高地址) 大端存储:低对高,高对低(低位存储在高地址,高位存储在低地址) 小端字节序: x86体系结构,arm指令只支持小端,数据支持大小端 ...
- LintCode 35: Reverse Linked List
LintCode 35: Reverse Linked List 题目描述 翻转一个链表. 样例 给出一个链表1->2->3->null,这个翻转后的链表为3->2->1 ...