Java多线程

目录

线程

线程的创建方式

[1. 继承Thread类](#1. 继承Thread类)

[2. 实现Runnable接口](#2. 实现Runnable接口)

3.继承TimerTask,定时线程

4.带有返回值的线程,Callable

[5.线程池 ExcuterService](#5.线程池 ExcuterService)

线程的生命周期

对线程的调度

沉睡-Thread.sleep()

让步-Thread.yeild()

合并-Thread.join()

线程的优先级


线程

一个进程有多个线程(进程是一个独立的工作任务和单元),线程由JVM(java虚拟机)控制。

协程:一个由用户控制的轻量级的线程。

如下面的代码所示,u1.run()属于方法调用,启动的是主线程main。u1.start()启动的是子线程,Thread-随机数。

线程的创建方式

1. 继承Thread类

java 复制代码
package com.demo2;

//Thread-整数,这就是子线程的名字
public class UserThread  extends  Thread{

	public void run()
	{
	
		System.out.println(Thread.currentThread().getName()+",run");
		
	}
}
java 复制代码
package com.demo2;

public class Test {
	
	public static void main(String[] args) {
		
       System.out.println(Thread.currentThread().getName()+",main函数");
       
		UserThread  u1  = new UserThread();
		u1.start();

	}

}

运行结果:

**注意:**一个线程启动以后,这个线程就不能再次启动了,这个线程已死亡。如果再次启动,这个线程会抛出线程状态异常。

2. 实现Runnable接口

Runnable接口是Thread类的父类,所以对于实现Runnable和继承Thread类来创建线程,实现Runnable比继承Thread更好,可以更好的扩展。

java 复制代码
package com.demo3;

/**
 * Runnable接口是Thread类的父类
 */
public class UserRunnable   implements Runnable{

	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+",run");
	}

}
java 复制代码
package com.demo3;

public class Test {
	
	public static void main(String[] args) {
		
		UserRunnable  ur =  new UserRunnable();
	
		//把这个实现了Runnable接口的对象,构建一个线程对象
		Thread  r1  = new Thread(ur);
		
		r1.start();
	}

}

运行结果:

3.继承TimerTask,定时线程

java 复制代码
package com.demo4;

import java.util.Date;
import java.util.TimerTask;

//定时线程
public class UserTask extends TimerTask {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+", run"+new Date());
	}

}
java 复制代码
package com.demo4;

import java.util.Timer;

public class Test {

	public static void main(String[] args) {

		// 定时线程的启动有特殊的方法

		UserTask ut = new UserTask();

		// 继承TimerTask不用这个方法,它是一个定时线程
//		Thread  t  = new Thread(ut);
//		t.start();
		
		
		// 建立一个定时器对象
		Timer  t =  new Timer();
		// 安排定时任务执行
		t.schedule(ut,1000,4000);
		
	}

}

t.schedule(ut, 1000, 4000) 这三个参数的意思是:

  • ut - 要执行的任务(必须是 TimerTask 的子类)
  • 1000 - 首次执行的延迟时间(毫秒) = 1秒后开始第一次执行
  • 4000 - 后续执行的间隔时间(毫秒) = 之后每4秒执行一次

运行结果:

4.带有返回值的线程,Callable

下面的代码演示了如何使用 CallableFuture 接口来实现有返回值的多线程任务 。与普通的Runnable不同,Callable可以返回执行结果和抛出异常。

执行流程:

  • 创建线程池Executors.newSingleThreadExecutor()
  • 创建任务new UserCall()
  • 提交任务es.submit(uc) 返回Future对象
  • 获取结果result.get() 阻塞等待任务完成
  • 关闭线程池es.shutdown()
java 复制代码
package com.demo7;

import java.util.concurrent.Callable;

public class UserCall  implements  Callable<Integer>{

	  // Callable的call方法可以有返回值和抛出异常
	public Integer call() throws Exception {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+",call方法");
		return 10;
	}

}
java 复制代码
package com.demo7;


import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Test {
	
	public static void main(String[] args) {
		
		// 创建单线程的线程池
		ExecutorService  es = 	Executors.newSingleThreadExecutor();
		
		// 创建Callable任务实例
		UserCall  uc = new UserCall();
		
		// 提交任务到线程池,返回Future对象
		Future<Integer>  result = es.submit(uc);
		
		try {
			// 获取任务执行结果(会阻塞直到任务完成)
			System.out.println("返回值:"+result.get());
			
			// 关闭线程池
			es.shutdown();
			
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

运行结果:

5.线程池 ExcuterService

下面的代码演示了如何使用 Java线程池 来执行一个实现了 Runnable 接口的任务。它创建了一个单线程的线程池,然后在这个线程中执行循环打印任务。

java 复制代码
package com.demo8;

public class UserRun1  implements Runnable{

	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<5;i++)
		{
			System.out.println(Thread.currentThread().getName()+","+i);
		}
	}

}
java 复制代码
package com.demo8;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
	
	public static void main(String[] args) {
		
		// 创建单线程的线程池
		ExecutorService  es = Executors.newSingleThreadExecutor();
	
		// 提交Runnable任务到线程池执行
		es.execute(new UserRun1());
		
		// 关闭线程池(不再接受新任务)
		es.shutdown();
	}

}

Executors.newSingleThreadExecutor():

  • 创建只有一个线程的线程池
  • 任务会按提交顺序依次执行
  • 线程会一直存在,可重复使用

execute() vs submit():

java 复制代码
// execute() - 用于Runnable,无返回值
es.execute(runnableTask);

// submit() - 可用于Runnable和Callable,返回Future对象
Future<?> future = es.submit(runnableTask);

运行结果:

线程的生命周期

  1. 创建线程对象

2.线程进入可运行状态 ,可以运行,JVM来调度执行

  1. 进入到运行状态

  2. 对线程的调度(沉睡,让步,合并,线程同步机制,线程通信机制,JUC线程机制)

5.死亡

对线程的调度

沉睡-Thread.sleep()

让当前正在运行的线程睡眠,当睡眠时间到,线程再次进入可运行状态,再次执行还是由JVM调度。

java 复制代码
package com.thread1;

public class UserThread  extends Thread {
	
	public void  run()
	{
		System.out.println(Thread.currentThread().getName()+",线程执行run方法开始");
		
		try {
			//Thread表示当前线程
			//让当前正在运行的线程睡眠
			//睡眠时间到,线程再次进入可运行状态,再次执行还是由JVM调度
			Thread.sleep(6*1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println(Thread.currentThread().getName()+",线程执行run方法之后");
	
	}

}
java 复制代码
package com.thread1;


public class Test {
	
	public static void main(String[] args) {
		
		for(int i=0;i<5;i++)
		{
			UserThread u1 = new UserThread();
			u1.start();
			
		}
	}

}

运行结果:

让步-Thread.yeild()

当前的线程进行让步,即让出执行权,可能选择让或不让。

java 复制代码
package com.thread2;

public class UserThread   extends Thread{
	
	public void run()
	{
		System.out.println("A");
		
		//让步,让出执行权,可能选择让或不让
 
		 Thread.yield(); 
		 
		System.out.println("B");
		
		//AABB或ABAB
	}

}
java 复制代码
package com.thread2;;

public class Test {
	
	public static void main(String[] args) {
		
		UserThread  u1  = new UserThread();
		UserThread  u2  = new UserThread();
		
		u1.start();
		u2.start();
	}

}

运行结果:

合并-Thread.join()

合并线程去执行。

java 复制代码
package com.thread3;

public class UserThread  extends Thread{
	
	int sum =0;
	
	public void run()
	{
		
		for(int i=0;i<=100;i++)
		{
			
			sum += i; 
			
		}

	}
	
	public int  getSum()
	{
		return this.sum;
	}
	

}
java 复制代码
package com.thread3;

public class Test {
	
	public static void main(String[] args) {
		
		UserThread  u1  = new UserThread();
		u1.start();
		
		try {
			//主线程和子线程的生命周期是隔离的
			//合并到主线程执行
			u1.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println("得到子线程的值为:"+u1.getSum());
		
		
		
	}

}

运行结果:

线程的优先级

线程的优先级取值1..10,但是不能够绝对保证优先级高的线程最先启动,只是在一段时候内,最先运行的概率高一点。

java 复制代码
package com.demo10;

public class UserThread   extends Thread{
	
	public void  run()
	{
		System.out.println(Thread.currentThread().getName()+",run...");
	}

}
java 复制代码
package com.demo10;

public class Test {
	
	public static void main(String[] args) {
		
		UserThread  u1 = new UserThread();
		UserThread  u2 = new UserThread();
		UserThread  u3 = new UserThread();
		
		//线程的优先级取值1..10,但是不能够绝对保证优先级高的线程最先启动
		//在一段时候内,最先运行的概率高一点
		u3.setPriority(Thread.MAX_PRIORITY);
		u1.setPriority(Thread.MIN_PRIORITY);
		
		u1.start();
		u2.start();
		u3.start();
	}
	
}

运行结果:

相关推荐
小年糕是糕手1 小时前
【C语言】C语言预处理详解,从基础到进阶的全面讲解
linux·c语言·开发语言·数据结构·c++·windows·microsoft
Charles豪1 小时前
MR、AR、VR:技术浪潮下安卓应用的未来走向
android·java·人工智能·xr·mr
TeleostNaCl1 小时前
SMBJ 简单使用指南 实现在 Java/Android 程序中访问 SMB 服务器
android·java·运维·服务器·经验分享·kotlin
我不是混子1 小时前
Java的SPI机制详解
java·后端
武子康2 小时前
Java-131 深入浅出 MySQL MyCat 深入解析 schema.xml 配置详解:逻辑库、逻辑表、数据节点全攻略
xml·java·数据库·mysql·性能优化·系统架构·mycat
我就要用Cx3302 小时前
微服务配置管理
java·运维·微服务
Seven972 小时前
剑指offer-33、丑数
java
okra-2 小时前
文件测试测试用例
java·服务器·eclipse
高山有多高2 小时前
从 0 到 1 保姆级实现C语言双向链表
c语言·开发语言·数据结构·c++·算法·visual studio
努力也学不会java2 小时前
【Java并发】深入解析ConcurrentHashMap
java·juc·hash table