多线程
进程
- 是指一个内存中运行的应用程序,每个进程都有一个独立的空间(都有各自的堆栈,不会共享)
线程:
- 是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行。一个进程最少有一个线程。
- 线程实际上是在进程基础上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程。
线程调度
分时调度
- 所有线程轮流使用CPU使用权,平均分配每个线程占用CPU的时间
抢占式调度
- 优先让优先级高德线程使用CPU,如果现成的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
- CPU使用抢占式调度模式多个
同步与异步
同步:排队执行,效率低,但是安全。
异步:同时执行,效率高,但是数据不安全。
并发与并行
并发:指两个或多个事件在同一个时间段内发生。
并行:指两个或多个事件在同一个时刻发生(同时发生)。
线程常见的两种方式,继承Thread 和 实现Runnable
public class Demo01 {
/**
* 多线程技术
* @param args
*/
public static void main(String[] args) {
//Thread
MyThread m = new MyThread();
//开启一个线程
m.start();
//主线程执行
for(int i=0;i<10;i++){
System.out.println("main方法" + i);
}
}
}
public class MyThread extends Thread{
/**
* run方法就是线程要执行的方法
*/
@Override
public void run() {
//这里的代码是新的执行路径
//此时的执行路径的触发方式,不是调用run方法,而是通过thread对象的star()来启动任务
for (int i=0;i<10;i++){
System.out.println("run方法实现" + i);
}
}
}
每个线程都拥有自己的栈空间,共用一份堆内存
/**
* 多线程技术
* 实现Runnable 与 继承Thread相比有如下优势:
* 1. 通过创建任务,然后给线程分配的方式来实现的多线程,更适合多个线程同时执行相同任务的情况。
* 2. 可以避免单继承所带来的局限性,(Java中不允许多继承,但是可以多实现)
* 3. 任务与线程本身是分离的,提高了程序的健壮性
* 4. 后续学习的线程池技术,接受Runnable类型的任务,不接受Thread类型的线程
*/
public class Demo01 {
/**
* 多线程技术
* @param args
*/
public static void main(String[] args) {
//实现Runnable
//1. 创建一个任务对象
MyRunnable myRunnable = new MyRunnable();
//2. 创建一个线程,并分配一个任务
Thread thread = new Thread(myRunnable);
//3. 执行这个线程
thread.start();
for(int i=0;i<10;i++){
System.out.println("main中的方法(主线程)" + i);
}
}
}
/**
* 用于给线程执行的任务
*/
public class MyRunnable implements Runnable {
@Override
public void run() {
//线程的任务
for (int i=0;i<10;i++){
System.out.println("Runnable --这里的线程 " + i);
}
}
}
有时使用Thread比较简洁,
public class Demo02 {
/**
* 匿名内部类
* @param args
*/
public static void main(String[] args) {
//使用Thread其有很简洁的写法
//创建一个对象,通过匿名内部类来开辟一个新线程,只调用一次方法
new Thread(){
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("Thread这里开辟的线程 " + i);
}
}
}.start();//只调用一次.start()方法
for(int i=0;i<10;i++){
System.out.println("main中的方法(主线程)" + i);
}
}
}
设置和获取线程名称
public class Demo01 {
/**
* 多线程技术
* @param args
*/
public static void main(String[] args) {
//如何获取 当前 线程的名称
System.out.println(Thread.currentThread().getName());
//如何设置线程名称
new Thread(new MyRunnable(),"名称XX").start();
//获取线程名称
TThread t = new Thread(new MyRunnable());
t.start();
//获取线程名称
new Thread(new MyRunnable()).start();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
}
线程休眠sleep
public class Demo01 {
/**
* 多线程技术
* @param args
*/
public static void main(String[] args) throws InterruptedException {
//线程的休眠 sleep
for (int i=0;i<10;i++){
System.out.println("run方法实现" + i);
//1000毫秒,线程的指定时间休眠
Thread.sleep(1000);
}
}
}
线程阻塞
线程阻塞不是sleep,简单理解为:所有消耗时间或者比较消耗时间的操作。常见的文件读取,代码等待在那个位置等文件读完,或者等待用户输入,我们常称为耗时操作
线程的中断
public class Demo04 {
public static void main(String[] args) {
//线程的中断
//一个线程是一个独立的执行路径,它是否应该结束,应该由其自身决定
//匿名
//new Thread(new MyRunnable()).start();
Thread t1 = new Thread(new MyRunnable());
t1.start();
for (int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName() + ":" + i);
//每隔1000毫秒,打印一次
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//给线程t1增加中断标记,
t1.interrupt();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName() + ":" + i);
//每隔1000毫秒,打印一次
try {
Thread.sleep(1000);
} catch (InterruptedException e) {//线程中断的异常
//e.printStackTrace();
System.out.println("发现中标记,线程自杀");
return;
}
}
}
}
}
守护进程
public class Demo04 {
public static void main(String[] args) {
//线程:分为守护线程和用户线程
//用户线程:当一个 进程 不包含任何存活的用户线程时,进行结束。
//守护线程:守护用户线程的,当最后一个用户线程结束后,所有守护线程自动死亡
Thread t1 = new Thread(new MyRunnable());
//直接创建的线程是用户线程,
//设置为守护线程,一定要在启动之前去设置,设置 t1为主线程
t1.setDaemon(true);
t1.start();
for (int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName() + ":" + i);
//每隔1000毫秒,打印一次
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName() + ":" + i);
//每隔1000毫秒,打印一次
try {
Thread.sleep(1000);
} catch (InterruptedException e) {//线程中断的异常
e.printStackTrace();
}
}
}
}
}
线程安全和不安全
public class Demo05 {
public static void main(String[] args) {
//线程不安全
//创建一个任务,多态
Runnable runnable = new Ticket();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
}
/**
* 创建任务类,创建一个任务对象,交给多个线程执行
*/
static class Ticket implements Runnable{
//票数
private int counts = 10;
@Override
public void run() {
//只要票没有卖完就接着卖
while(counts>0){
//卖票
System.out.println("正在准备卖票:");
//休眠1秒,放大卖票的时间,放大出错的几率
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
counts--;
System.out.println("出票成功,余票:" + counts);
}
}
}
}
***************************************************************
"D:\Program Files\Java\jdk-14.0.2\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2020.1\lib\idea_rt.jar=63022:D:\Program Files\JetBrains\IntelliJ IDEA 2020.1\bin" -Dfile.encoding=UTF-8 -classpath D:\Users\ASUS\IdeaProjects\Demo\out\production\Demo com.kkb.demo.Demo05
正在准备卖票:
正在准备卖票:
正在准备卖票:
出票成功,余票:8
正在准备卖票:
出票成功,余票:9
正在准备卖票:
出票成功,余票:7
正在准备卖票:
出票成功,余票:6
正在准备卖票:
出票成功,余票:5
正在准备卖票:
出票成功,余票:4
正在准备卖票:
出票成功,余票:2
正在准备卖票:
出票成功,余票:3
正在准备卖票:
出票成功,余票:1
正在准备卖票:
出票成功,余票:-1
出票成功,余票:0
出票成功,余票:-2
Process finished with exit code 0
线程安全:
public class Demo05 {
/**
* 线程同步:synchronized
* @param args
*/
public static void main(String[] args) {
//线程不安全
//解决方案一:同步代码块
//格式: synchronized(锁对象){}
Runnable runnable = new Ticket();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
}
/**
* 创建任务类,创建一个任务对象,交给多个线程执行
*/
static class Ticket implements Runnable{
//票数
private int counts = 10;
private Object o = new Object();//多个线程用一把锁才能排队
@Override
public void run() {
//Object o = new Object();错误示范,
//应该是多个线程看一个锁对象,而不是各自的锁对象
//只要票没有卖完就接着卖
while(true){
synchronized (o){
if (counts>0){
//卖票
System.out.println("正在准备卖票:");
//休眠1秒,放大卖票的时间
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
counts--;
System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + counts);
}else {
break;
}
}
}
}
}
}
*********************************************************
"D:\Program Files\Java\jdk-14.0.2\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2020.1\lib\idea_rt.jar=63343:D:\Program Files\JetBrains\IntelliJ IDEA 2020.1\bin" -Dfile.encoding=UTF-8 -classpath D:\Users\ASUS\IdeaProjects\Demo\out\production\Demo com.kkb.demo.Demo05
正在准备卖票:
Thread-0出票成功,余票:9
正在准备卖票:
Thread-0出票成功,余票:8
正在准备卖票:
Thread-0出票成功,余票:7
正在准备卖票:
Thread-0出票成功,余票:6
正在准备卖票:
Thread-0出票成功,余票:5
正在准备卖票:
Thread-0出票成功,余票:4
正在准备卖票:
Thread-0出票成功,余票:3
正在准备卖票:
Thread-2出票成功,余票:2
正在准备卖票:
Thread-1出票成功,余票:1
正在准备卖票:
Thread-1出票成功,余票:0
Process finished with exit code 0
浙公网安备 33010602011771号