文章目录
1.进程、线程简介
1.1进程
进程(process):是程序的一次执行过程,或是正在运行的一个程序。动态过程:有它自身的产生、存在和消亡的过程。
1.2线程
线程(thread):进程可进一步细化为线程,是一个程序内部的一条执行路径
1.3线程分类
- 守护进程
- 用户进程
当一个用户线程结束后,JVM会检查系统中是否还存在其他用户线程,如果只剩下守护线程而没有用户线程的话,JVM就会终止。
2.创建多线程方法
2.1继承的方法
- 创建一个线程类,继承自
Thread
类 - 实现
run()
方法 - 创建一个该线程类的对象
- 调用
start()
方法启动线程,并执行run()
方法
public class TestThread {
public static void main(String[] args) {
MyThread my1 = new MyThread();
// 一个线程只能启动一次;start()方法步骤是:启动线程;调用run()方法;
my1.start();
for(int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
// 继承的方法创建多线程
class MyThread extends Thread{
@Override
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
2.2实现的方法
- 创建一个实现
Runnable
接口的类 - 实现
run()
方法 - 创建一个
Runnable
接口实现类的对象 - 将此对象作为形参传递给Thread类构造器中,创建Thread类的对象,此对象为一个线程
- 调用
start()
方法启动线程,并执行run()
方法
public class TestThreadRunnable {
public static void main(String[] args) {
MyThreadRunnable my1 = new MyThreadRunnable();
// 要启动线程必须使用start()方法
Thread t1 = new Thread(my1);
t1.start();
}
}
// 实现的方法创建多线程
class MyThreadRunnable implements Runnable{
@Override
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
2.3两种方式比较
实现的方式较优
- 避免Java单继承的局限性
- 如果多个线程要操作同一份资源,更适合使用实现的方式
3.Thread类的常用方法
方法名 | 功能 |
---|---|
start() | 启动线程并执行相应的run() 方法 |
run() | 子线程要执行的代码放入run() 方法中 |
currentThread() | 静态的,调取当前的线程 |
getName() | 获取此线程的名字 |
setName() | 设置此线程的名字 |
yield() | 调用此方法的线程释放当前CPU的执行权 |
join() | 在A线程中调用B线程的join()方法,表示,当执行到此方法,A线程停止执行,执行完B线程,A线程再接着执行 |
isAlive() | 判断当前线程是否存活 |
sleep(long l) | 显式的让当前线程睡眠l 毫秒 |
4.线程的调度
4.1调度策略
- 时间片
- 抢占式:高优先级的线程抢占CPU
4.2调度方法
- 同优先级线程组成先进先出队列,使用时间片策略
- 对高优先级,使用优先调度的抢占式策略
4.3线程的优先级
- 线程优先级范围:1 ~ 10
getPriority()
:返回线程优先值setPriority(int newPriority)
:改变线程的优先级- 线程创建时继承父线程的优先级
5.线程的生命周期
如图,线程的声明周期分为五种状态:
6.线程的同步机制(synchronized)
- 要求:所有的线程必须共用同一把锁
- 注意:在实现的方式中,考虑同步的话,可以使用this来充当锁,而继承的方式不允许这样
- 对于静态方法而言,使用当前类本身充当锁(反射)
6.1同步代码块
Object obj = new Object();
synchronized(obj/*同步监视器*/){ //(---->实现的方法创建多线程时,这里可以填this)
// 需要被同步的代码块(即为操作共享数据的代码)
// 同步监视器:由任何一个类的对象来充当,哪个线程获取此监视器,谁就执行大括号里被同步的代码。俗称:锁。
}
6.2同步方法
同步方法锁:this(创建线程的方法为实现时 才成立)
public synchronized void show(){
.....
}
6.3同步方法解决单例模式之懒汉式的线程安全问题
class Singleton{
private Singleton(){}
private static Singleton instance = null;
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
7.线程的通信
定义在Object类里面
- wait():令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问(释放锁)
- notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
- notifyAll():唤醒全部
- 此三个方法只有在同步代码块或者同步方法中才能使用,否则会抛出异常
8.生产者与消费者的问题
public class TestProduceConsume {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Prodecer p1 = new Prodecer(clerk);
Consumer c1 = new Consumer(clerk);
Thread t1 = new Thread(p1);
Thread t2 = new Thread(c1);
t1.setName("生产者线程");
t2.setName("消费者线程");
t1.start();
t2.start();
}
}
class Clerk{
// 产品数量
private int product;
// 生产产品
public synchronized void addProduct() {
if(product >= 20) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
product++;
System.out.println(Thread.currentThread().getName() + ": 生产了第 " + product + " 个产品");
notify();
}
}
// 消费产品
public synchronized void useProduct() {
if(product <= 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName() + ":" + "消费了第 " + product + "个产品");
product--;
notify();
}
}
}
// 生产者类
class Prodecer implements Runnable{
private Clerk clerk;
public Prodecer(Clerk clerk) {
super();
this.clerk = clerk;
}
@Override
public void run() {
System.out.println("生产者开始生产产品");
while(true) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.addProduct();
}
}
}
// 消费者类
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk) {
super();
this.clerk = clerk;
}
@Override
public void run() {
System.out.println("生产者开始生产产品");
while(true) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.useProduct();
}
}
}