Java零基础—多线程

目录

多线程的基本概念

进程:

多进程的作用:

多线程的作用:

线程的创建和启动

继承Thread类:

实现Runnable接口

线程的生命周期

线程的调度与控制

线程的同步

守护线程

定时器的使用


 

多线程的基本概念

线程指进程中的一个执行场景,也就是执行流程。每一个进程都是一个应用程序,都有独立的内存空间;同一个进程中的线程共享进程中的内存和资源(共享的内存是堆内存和方法区内存,栈内存不共享,每一个线程都有自己的栈内存),一个进程中可以启动多个线程。

进程:

一个进程对应一个应用程序。例如:在Windows操作系统下启动一个Word就表示启动了一个进程。在Java的开发环境下启动JVM,就表示启动了一个进程。

多进程的作用:

单进程计算机一次只能做一件事;对于单核计算机来讲,CPU只能在某个时间点上做一件事。双核或多核计算机在某个时间点上可以同时处理多件事情。多进程的作用不是提高执行速度,而是提高CPU的使用率。进程与进程之间的内存是独立的。

多线程的作用:

多线程的作用不是为了提高执行速度,而是为了提高应用程序的使用率。

线程的创建和启动

Java中虚拟机的主线程入口是main方法,用户可以自己创建线程,创建方式有两种:继承Thread类、实现Runnable接口(推荐)。

继承Thread类:

Thread类中创建线程最重要的两个方法为:

public void run()
public void start()

采用Thread类创建线程,用户只需要继承Thread类,覆盖Thread类中的run方法,父类Thread中的run方法没有抛出异常,那么子类也不能抛出异常,最后采用start启动线程即可。

public class ThreadTest01{
	public static void main(String[] args){
			//创建线程
			Thread t = new Processor();
			//启动线程
			t.start();
			
			t.run();//普通方法调用
			
			for(int i = 0; i < 50; i++){
					System.out.println("main---->" + i);
				}
		}
	
}

//定义一个线程
class Processor extends Thread{
	//重写run方法
	public void run(){
		for(int i = 0;i < 100;i++){
				System.out.println("run————>" + i);
			}
	}
}

实现Runnable接口

实现Runnable接口,并实现run方法

public class ThreadTest01{
	public static void main(String[] args){
			//创建线程
			Thread t = new Thread(new Processor());
			//启动线程
			t.start();
			
			for(int i = 0; i < 50; i++){
					System.out.println("main---->" + i);
				}
		}
	
}

//推荐这种方法,因为一个类实现接口之外,保留了类的继承
class Processor implements Runnable{
	
	//重写run方法
	public void run(){
		for(int i = 0;i < 100;i++){
				System.out.println("run————>" + i);
			}
	}
}

 

线程的生命周期

线程的生命周期存在五个状态:新建、就绪、运行、阻塞、消亡​

 

线程的调度与控制

通常我们的计算器只有一个CPU,CPU在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。在单CPU的机器上线程并不是并行运行的,只有在多个CPU上,线程才可以并行运行。Java虚拟机要负责线程的调度,取得虚拟机的使用权,目前有两种调度模型:分时调度模型和抢占式调度模型,Java中使用抢占式调度模型。

分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片。

抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的时间片相对多一些。

线程优先级分为三种:MAX_PRIORITY(最高级10)、MIN_PRIORITY(最低级1)、NORM_PRIORITY(标准)默认5。

Thread.sleep(毫秒);:sleep是一个静态方法,作用是阻塞当前线程。当一个线程遇到sleep的时候,就会睡眠,进入到阻塞状态,放弃CPU,腾出CPU时间片,给其它线程用,当睡眠时间到了,线程就会进入可运行状态,得到CPU时间片继续运行。如果线程在睡眠状态被中断了,就会抛出interruptedException异常。

interrupt();:利用异常的处理机制打断线程的休眠,interruptedException异常。

若要不利用异常的处理机制,而是要正常的终止线程的休眠,使用:p.run = false;(Processor p = new Processor();)

Thread.yield();:静态方法,与sleep类似, 只是不能有用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会,让位时间不固定。

Thread.join();:成员方法,当前线程可以调用另一个线程的join方法,调用后当前线程被阻塞不再执行,直到被调用的线程执行完毕,当前线程才会被执行。该方法称为线程的合并。

线程的同步

线程同步是为了数据的安全,而暂时放弃了效率。在满足以下条件时要使用线程同步:

1、必须是多线程环境;2、多线程环境共享同一个数据;3、共享的数据涉及到修改操作;

使用线程同步,把需要同步的代码,放到同步语句块synchronized(this){}中或在对应的方法前加关键字synchronized。当一个线程t1执行到此处,遇到了synchronized关键字,就会去找this的对象锁,如果找到this对象锁,则t1进入同步语句块中执行,当同步语句块中的代码执行结束之后,该t1线程会归还this的对象锁。在t1线程执行同步语句块的过程当中,如果t2线程也执行此处遇到synchronized关键字,也会去找this的对象锁,但是该对象锁被t1线程持有,所以t2线程只能在这里等待this对象的归还。所以保证了语句块中的代码永远只有一个线程执行。

synchronized(this){

}

类锁:synchronized添加到静态方法上,线程执行此方法的时候会找类锁,与对象锁无关。类锁只有一把。

死锁:

public class DeadLock{
	public static void main(String[] args){
		Object o1 = new Object();
		Object o2 = new Object();
	
		Thread t1 = new Thread(new T1(o1,o2));
		Thread t2 = new Thread(new T2(o1,o2));
	
		t1.start();
		t2.start();
		}
	}

class T1 implements Runnable{
	Object o1;
	Object o2;
	T1(Object o1,Object o2){
		this.o1 = o1;
		this.o2 = o2;
		}
		
	public void run(){
		synchronized(o1){
			try{
				Thread.sleep(1000);
				}catch(InterruptedException e){}
				synchronized(o2){
					}
			}
		}
	}
	
class T2 implements Runnable{
	Object o1;
	Object o2;
	T2(Object o1,Object o2){
		this.o1 = o1;
		this.o2 = o2;
		}
		
	public void run(){
		synchronized(o2){
			try{
				Thread.sleep(1000);
				}catch(InterruptedException e){}
				synchronized(o1){
				}
			}
		}
	}

守护线程

线程可以分为守护线程和用户线程两类。所有的用户线程生命周期结束,守护线程的生命周期才会结束。只要有一个用户线程存在,守护线程就不会结束。例如:Java中的垃圾回收器就是一个守护线程,只有应用程序中所有的线程结束,它才会结束。

定时器的使用

每隔一个固定的时间,执行一段代码。

import java.text.*;
import java.util.*;
public class TimerTest{
	public static void main(String[] args) throws Exception{
		
		//创建定时器
		Timer timer = new Timer();
		
		//指定定时任务2021-03-30 21:22:00 000开始,每隔10秒钟打印输出当前时间
		timer.schedule(new LogTimerTask(),
					   new SimpleDateFormat("yyyy-MM-dd HH:mm:ss sss").parse("2021-03-30 21:22:00 000"),
					   10*1000);
		}
	}
	//指定任务
	class LogTimerTask extends TimerTask{
		public void run(){
			System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss sss").format(new Date()));
			}
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值