栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java多线程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java多线程

多线程
  • 并行和串行
  • 并行:多个任务同时执行,效率高。
  • 串行:多个任务依次执行,效率低
  • 单核和多核CPU
  • 单核:如:只有一个人帮干活
  • 多核:有多个人帮你干活
  • 线程和进程
  • 进程(Process):正在运行的一个程序称为进程(word 、记事本)
  • 线程(Thread):线程就是进程中的一个任务.
  • 单线程和多线程
  • 如果一个进程中只有一个线程,称为单线程的程序。
  • 如果一个进程中包含两个或者两个以上的线程,称为多线程程序。
  • 进程负责分配内存,多线程共享进程分配的内存
  • 进程的任务之一是向操作系统申请内存
  • 线程向进程申请内存
  • 多线程共享进程分配的内存
  • 线程调度器与调度算法
  • 多个线程谁先执行?线程的运行过程是由线程调度器来负责的。
  • 线程调度器有两个调度算法:时间片轮换调度与抢占式调度
Java对多线程的支持
  • java多线程解决了程序并发执行
创建线程的方式
  • 串行
public class DemoChuanXing {
	public static void main(String[] args) {
		
		a();
		System.out.println("main");
	}
	private static void a() {
		b();
		System.out.println("a");	
	}
	private static void b() {
		System.out.println("b");	
	}
}
  • 继承Thread类创建线程
public class MyThread extends Thread{
	
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+"="+i);
		}
	}
}
public class Test {
	public static void main(String[] args) {
		
		MyThread myThread=new MyThread();
		//启动线程,线程会自动调用run方法
		myThread.start();	
	}
}
  • 关于主线程
  • main方法启动时会自动创建一个线程,称为主线程。
  • 子线程需要在主线程中创建。
  • 关于线程的名称
  • Thread.currentThread()获取当前线程
  • Thread.currentThread().getName()获取当前线程的名称
  • 主线程名称默认是main
  • 子线程名称默认是Thread-00 | 01 | 02
  • 修改线程的名称,调用setName方法
  • Thread.currentThread().setName(“主线程”);
  • t.setName(“子线程”);
  • 实现Runnable接口创建子线程
public class MyThread implements Runnable{
	

	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+"="+i);
		}
	}
}
public class Test {
	public static void main(String[] args) {
		
		Thread.currentThread().setName("主线程");
		MyThread myThread=new MyThread();
		//将Runnable接口包装到Thread类中
		Thread t=new Thread(myThread);
		t.setName("子线程");
		t.start();
		
		for(int i=0;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+"="+i);
		}
	}
}

Runnable接口是函数式接口,因此可以使用lambda表达式实现线程。

public class Test1 {
	public static void main(String[] args) {
		
		Runnable runnable=()->{
			for(int i=0;i<100;i++) {
				System.out.println(Thread.currentThread().getName()+"="+i);
			}
		};
		new Thread(runnable).start();
		
		for(int i=0;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+"="+i);
		}
	}
}

实现Callable接口

  • 与Runnable相比,Callable可以有返回值,返回值通过FutureTask进行封装。
ublic class MyCallable implements Callable{

	@Override
	public Integer call() throws Exception {
		return 45;
	}
}

public class Test {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		MyCallable myCallable=new MyCallable();
		FutureTask f=new FutureTask<>(myCallable);
		Thread thread=new Thread(f);
		thread.start();
		System.out.println(f.get());
	}
}
继承类与实现接口的方式有什么区别
  • java不支持多重继承,因此继承了Thread类就无法继承其他类,但是可以实现多个接口
  • 类可能只要求可执行就行,继承整个Thread类开销过大。
主线程与子线程
  • main方法启动时,JVM自动创建了主线程
  • main方法中new的线程是子线程
线程的基础机制
  1. 让步yield
  • 一个运行中的线程想要放弃执行的权利
  • 此时线程调度器会选择另一个可运行的线程来执行,不过,调度器也可以忽略这个通知
  • yield只是放弃了本时间片的执行,放弃后又回到就绪队列重新排队。
public class ThreadYield {
	public static void main(String[] args) {
		
		Runnable run=()->{
			for(int i=0;i<100;i++) {
				System.out.println(Thread.currentThread().getName()+"="+i);
				Thread.yield();
			}
		};
		new Thread(run).start();
		new Thread(run).start();
	}
}
  1. 休眠sleep
  • 当线程休眠时,它放弃了执行的权利,加入到等待对列,什么都不做,然后等到休眠时间到了再醒过来,加入可运行队列。
public class Sleep {
	public static void main(String[] args) {
		
		Runnable run=()->{
			while(true) {
				System.out.println(new Date());
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		Thread t=new Thread(run);
		t.start();
	}
}

解析:

  • sleep时,线程休眠了,在休眠期间不会进入到就绪队列
  • 当休眠时间结束后,进入就绪队列排队
  • sleep方法会抛出编译时异常InterruptedException(中断)
  1. 优先级priority

Thread类中定义了三个优先级常量

  • MAX_PRIORITY=10
  • NORM_PRIORITY=5
  • MIN_PRIORITY=1

线程优先级

  • 决定了那个线程更容易获取CPU时间片
  • 虽然线程调度器选择哪一个线程运行是由很多因素决定的,但是调度器确实会让优先级高的线程获得CPU
  • 对于两个优先级不同的线程来说,优先级高的线程会得到更多的执行时间。
  • 但是优先级高的线程不一定先执行
public class Priority {
	public static void main(String[] args) {
		Runnable run=()->{
			for(int i=0;i<100;i++) {
				System.out.println(Thread.currentThread().getName()+"="+i);
			}
		};
		Thread t1=new Thread(run);
		Thread t2=new Thread(run);
		//设置优先级别
		t1.setPriority(Thread.MAX_PRIORITY);
		t2.setPriority(1);	
		t1.start();
		t2.start();
	}
}
  1. 后台线程(background:后台 daemon:守护)

进程退出是如何界定的?

  • 当一个进程中的所有线程都结束了,这个进程就退出了.当一个进程中只要有一个线程还在运行,那么这个进程就不能退出

为什么要后台线程呢?

  • 后台线程是否在运行,不影响进程的结束。所有的非后台进程都结束了,进程就退出了。

后台线程使用场景

  • 监视程序
  • JVM的垃圾回收线程
	public static void main(String[] args) {
		
		Runnable run=()->{
			while(true) {
				System.out.println(new Date());
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		Thread t=new Thread(run);
		//将t设置为守护线程,t是否在运行不影响程序的退出。
		t.setDaemon(true);
		t.start();
	}
  1. 线程间的协作

线程联合join

  • join 方法是让一个线程等待另一个线程执行完毕后再继续执行执行
class A extends Thread{
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+"="+i);
		}
	}
}
class B extends Thread{
	private A a;
	
	public B(A a) {
		this.a = a;
	}
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			try {
	
				a.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"="+i);		
		}
	}
}
public class Test {
	public static void main(String[] args) {
		A a=new A();
		B b=new B(a);
		a.setName("牛牛牛牛牛");
		b.setName("*********");
		a.start();
		b.start();
	}
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/318419.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号