Java- 多线程学习笔记

10 篇文章 0 订阅

Java- 多线程学习笔记

一、进程与线程的区别

​ 进程:进程是相对操作系统进行资源和调度的基本单位,一个操作系统可以同时执行多个进程(每一个应用程序就是一个进程)。

线程:线程是相对一个应用程序进行资源分配和调度的基本单位(一个应用程序可以有多个子线程),但每一个应用程序至少有一个主线程。

二、如何使用java创建多线程的应用程序

​ 方法一:

​ 创建步骤:

​ 1、定义类继承Thread类;

​ 2、重写run()方法

​ 3、通过start()方法进行启动多线程

​ 代码如下:

public class ThreadTestDemo {

		public static void main(String[] args) {
			
			// 如何启动一个新的线程
			MyThread myThread = new MyThread();
			// 调用start()方法
			myThread.start(); // 自动调用run()方法
				
			for(int i = 0;i < 100;i++) {
				System.out.println("主线程中输出:i=" + i);
			}
			
		}
	
	
}

// 创建子线程的类
class  MyThread extends Thread{
	
	
		@Override
		public void run() {
				for(int i = 0;i < 100;i++) {
					System.out.println("MyThread线程中输出:i=" + i );
				}
		}
	
	
}

方法二:通过实现Runnable接口,代码如下:

// 方法二:
class MyThread2 extends TestDemo1 implements Runnable{

	@Override
	public void run() {
		for(int i = 0;i < 100;i++) {
			System.out.println(Thread.currentThread().getName() +"线程中输出:i=" + i );
		}
	}
	
}

使用此方法实现的多线程程序,启动需要使用Thread类实例化,调用start()方法启动子线程,代码如下:

MyThread2 thread2 = new MyThread2();
Thread thread = new Thread(thread2, "子线程2");
thread.start();

三、线程的生命周期

​ 线程的生命周期分为五个阶段,分部是:新建状态、就绪状态、运行状态、阻塞状态、死亡状态,如图:

在这里插入图片描述

新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

运行状态:
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。

其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

四、线程调度

4.1 多线程执行随机性

​ 多线程的程序在多线程同时在执行的过程中,由于每个线程执行run()方法是根据系统的调度来决定的,所以多线程在执行的先后次序上有一定的随机性,其代码代码如下:

public class ThreadRandomTest {
	
	
			public static void main(String[] args) {
				
				Thread[] threads = new Thread[10];
				for(int i = 0;i < 10;i++) {
					threads[i] = new RandomThread("RandomThread" + i);
				}
				
				for(Thread thread:threads) {
						thread.start();
				}
				
			}
	

}


class RandomThread extends Thread{

	public RandomThread(String name) {
		super(name);
	}
	
	@Override
		public void run() {
				try {
					Thread.sleep(1000);
					System.out.println(Thread.currentThread().getName());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
		}

	
}

4.2 线程中断

​ 使用sleep()方法让当前的线程阻塞,代码如下:

public class SleepThreadDem {

	
	public static void main(String[] args) {
		SleepThread sleepThread = new SleepThread();
		SleepThread sleepThread2 = new SleepThread();
		System.out.println("是否激活(new):" + sleepThread.isAlive());
		sleepThread.start();
		sleepThread2.start();
		System.out.println("是否激活(start):" + sleepThread.isAlive());
		
		
		 for(int i = 0;i < 10;i++) {
			 System.out.println(Thread.currentThread().getName() + "输出i=" + i);
			 if(i == 2) {
				 	try {
				 		// 使得当前线程阻塞,进入睡眠状态
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			 }
		 }
		
		
	}
}


class SleepThread extends Thread{
	@Override
	public void run() {
		System.out.println("是否激活(run):" + this.isAlive());
		 for(int i = 0;i < 10;i++) {
			 System.out.println(Thread.currentThread().getName() + "输出i=" + i);
			 if(i == 3) {
				 	try {
				 		// 使得当前线程阻塞,进入睡眠状态
				 		System.out.println("是否激活(sleep):" + this.isAlive());
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			 }
		 }
	}
	
	
}

4.3 线程让步

​ yield()方法与sleep()方法相似,都可让当前正在运行中的线程暂停,不过yield()方法不会阻塞当前线程

public class YieldThreadDemo {
	
		public static void main(String[] args) {
			
			YieldThread yi1 = new YieldThread("呃呃呃");
			YieldThread yi2 = new YieldThread("鹅鹅鹅");
			yi1.start();
			yi2.start();
			
		}
	
	
}

class YieldThread extends Thread {

	public YieldThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + "输出数字:" + i);
			if (i == 3) {
					System.out.println("当i=3时,线程"+Thread.currentThread().getName() +"让步,执行相同或者更高级优先级线程:");
					Thread.yield();
			}
		}
	}

}
4.4 线程插队

使用join进行插队,其代码如下:

public class JoinThreadDemo {

	public static void main(String[] args) {
		JoinThread joinThread1 = new JoinThread("子线程-1");
		JoinThread joinThread2 = new JoinThread("子线程-2");
		joinThread1.start();
		joinThread2.start();

		try {
			joinThread1.join(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		try {
			joinThread2.join(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		// 主线程
		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + "输出i=" + i);
		}

	}

}

class JoinThread extends Thread {

	public JoinThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "线程运行开始!");
		for (int i = 0; i < 5; i++) {
			System.out.println("线程:" + Thread.currentThread().getName() + "输出" + i);
		}
		System.out.println(Thread.currentThread().getName() + "线程运行结束!");
	}

}

​ join()方法-线程插队,即当前子线程调用join()方法后,线程进入阻塞状态直到子线程执行完成,才会继续执行。

五、线程同步

当多个线程同时访问一个共有资源,可能发生线程同步,使用场景 如:多个窗口买同趟车票,有可能重买或多买,代码如下:

public class TicketsThreadDemo {

	public static void main(String[] args) {
		
		TicketsThread t = new TicketsThread();
		
		new Thread(t, "A窗口").start();
		new Thread(t, "B窗口").start();
		new Thread(t, "C窗口").start();
		new Thread(t, "D窗口").start();
		
		
	}
	
	
	
}


class TicketsThread implements Runnable{

	private int tickets = 10;
	
	@Override
	public   void run() {
			while(tickets > 0) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "卖出票 " + tickets--);
			}
	}
	
}
	

​ 执行结果:

在这里插入图片描述

​ 解决此次问题可以在run()方法中添加synchronized关键字使得run()方法可以同步,多线程的程序执行此方法时,此方法进行锁定直到执行完成,其他线程调用可以执行,这样可以保证程序逻辑正常,修改代码如下:


class TicketsThread implements Runnable{

	private int tickets = 10;
	
	@Override
	public synchronized  void run() {
			while(tickets > 0) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "卖出票 " + tickets--);
			}
	}
	
}
	

​ 执行效果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值