多线程基础学习笔记

了解多线程

进程与线程

进程是一个电脑上的程序,线程是进程中的执行单位
进程拥有许多线程与堆、方法区,线程拥有自己的栈、程序计数器、本地方法栈

并发与并行

并发:同一时刻多个任务都执行
并行:同一时间段多个任务执行

为什么要使用多线程

单处理器:io操作与cpu操作不能同时运行,多线程可以提高程序运行效率
多处理器:使用单线程无法同时利用所有cpu
服务器:需要同时响应多个用户请求

使用多线程需要处理的问题

1,线程安全
2,死锁
3,内存泄漏

多线程实现方式

继承Thread类

1,构造Thread子类,重写run方法
2,创建该子类实例对象,调用start方法
特点:java只能继承一个父类

为什么不直接使用run方法

执行run只能运行里面的代码,start才能启动一个线程

实现Runnable接口

1,构造Runnable接口子类实例对象,重写run方法
2,创建该子类实例对象
3,调用有参的Thread构造方法,调用start方法
特点:java可以实现多个接口,避免单继承的局限性
更好的处理共享资源的情况

实现Callable接口

1,构造Callable接口子类实例对象,重写call方法
2,创建该子类实例对象
3,调用有参的FutureTask构造方法
4,调用有参的Thread构造方法,调用start方法
特点:有返回值,可声明抛出异常

代码:

扫描二维码关注公众号,回复: 12786084 查看本文章
public class Test2 {
    
    

	public static void main(String[] args) throws InterruptedException, ExecutionException {
    
    
		Thread1 t1 = new Thread1();
		t1.start();
		Thread2 t2 = new Thread2();
		new Thread(t2).start();
		Thread3 t3 = new Thread3();
		FutureTask<Object> f = new FutureTask<>(t3);
		Thread t = new Thread(f);
		t.start();
		System.out.println(f.get());
	}
}

class Thread1 extends Thread{
    
    
	public void run() {
    
    
		for(int i = 0; i < 10; i++) {
    
    
			System.out.println(Thread.currentThread().getName() + i);
		}
	}
}

class Thread2 implements Runnable{
    
    
	public void run() {
    
    
		for(int i = 0; i < 10; i++) {
    
    
			System.out.println(Thread.currentThread().getName() + i);
		}
	}
}

class Thread3 implements Callable<Object>{
    
    
	public Object call() throws Exception {
    
    
		// TODO Auto-generated method stub
		for(int i = 0; i < 10; i++) {
    
    
			System.out.println(Thread.currentThread().getName() + i);
		}
		return 10;
	}
}

线程的生命周期

新建

对象创建时

可运行

调用start方法后变为可运行状态
分为就绪与运行

阻塞

一般与锁有关
等待获取锁时发生阻塞
发出IO请求时也会发生

等待

使用无参的join、wait等方法会发生等待
其他线程使用notify、notifyAll后线程进入就绪

定时等待

使用有参的sleep、wait、join会定时等待
其他线程使用notify、notifyAll后线程进入就绪
时间到也会进入就绪

死亡

执行完毕,或者抛出异常,错误时线程死亡
死亡后无法进入其他状态

线程调度

强占调度:按优先级争取CPU资源
定时调度:线程获得定时大小的时间片并执行

优先级

高优先级容易抢到CPU资源
优先级分为1到10
优先级改变使用setPriority方法

让步

线程进入就绪状态,放弃cpu资源
使用yield方法

休眠

使用sleep方法使线程休眠

插队

A线程插入B线程中,只有A运行结束才能运行B
使用join方法

后台

线程分前台与后台,默认情况下为前台
前台线程全部结束,程序结束
需要在start方法使用前使用setDeamon方法

多线程同步

线程安全

有延时时会引发安全问题,与数据库类似

同步代码块

使用synchronized方法锁住一个对象,以下代码块同步

对象任意,但必须相同,代码块未执行时标记值为1,使用时为0,为0时其他线程无法执行代码块

同步方法

用synchronized修饰方法,被修饰方法同步

方法被锁时上锁的对象为调用方法的对象

同步静态方法

不创建对象,同步静态方法的锁为该方法的class对象

synchronized缺点:每次线程调用时都需要判断锁的标记值,消耗大
线程需要一直等待直到拿到锁

同步锁

使用Lock接口、ReentrantLock实现类构造锁,使用lock方法与unlock方法可以实现线程同步
一般在finally中写unlock方法

线程多次申请取锁失败后,不再等待,较为灵活

多线程通信

wait与sleep的区别:

sleep使用者为线程,wait使用对象为同步锁对象
wait放弃锁对象,sleep不放弃
使用wait线程不会自动苏醒,需要notify、notifyAll。sleep方法(和有参的wait)执行完成后,线程会自动苏醒。

notify、notifyAll的区别

notify唤醒同步锁上第一个等待的线程(第一个调用wait的线程),notifyAll唤醒所有等待的线程

猜你喜欢

转载自blog.csdn.net/sekever/article/details/114680283