多线程基础知识
1、进程:在操作系统中运行的程序就是进程。(例如:看视频)
一个进程可以有多个线程。(例如:视频中的画面、声音、看字幕)
2、线程:线程是进程中的一个执行单元,负责当前进程中程序的执行。
核心概念:
1)线程就是独立的执行路径;多线程指多条路径;
2)在程序运行时,即使自己没有创建线程,后台也会存在多个线程,如gc线程、主线程;
3)main()称之为主线程,为系统的入口点,用于执行整个程序;
4)在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序不能人为干预;
5)对同一份资源操作时,会存在资源抢夺问题,需要加入并发控制;
6)线程会带来额外的开销,如CPU调度时间、并发控制开销;
7)每个线程在自己的工作内存交互,加载和存储内存控制不当会造成数据不一致。
3、创建线程
1)继承Thread类
将类声明为Thread的子类,这个子类要重写run方法,然后可以分配并启动子类的实例。
class MoreThread extends Thread{
string name;
MoreThread(string name){
this.name = name;
}
public void run(){
//线程体
}
}
//以下代码将创建一个线程并启动它:
MoreThread mt = new MoreThread("张豆豆"); //创建子类对象
mt.start(); //启动,开启新的线程,不一定立即执行,系统安排调度分配执行
2)实现Runnable接口
声明一个实现Runnable接口的类。这个类实现了run方法,然后分配类的实例,在创建Thread时作为参数传递,并启动。
class MoreThread implements Runnable{
string name;
MoreThread(string name){
this.name = name;
}
public void run(){
//线程体
}
}
//以下代码将创建一个线程并启动它:
(1) //创建实现类对象
MoreThread mt = new MoreThread("张豆豆");
//创建代理类对象
Thread t = new Thread(mt);
//启动
t.start();
(2)//创建代理类对象,并启动
new Thread(mt).start();
(3) //匿名
new Thread(new MoreThread()).start();
3)实现Callable接口 (JUC并发编程)
class CDownloader implements Callable{
private String url;
private String fname;
public CDownloader(String url,String fname) {
this.url = url;
this.fname = fname;
}
@Override
public Object call() throws Exception {
WebDownloader downloader = new WebDownloader();
downloader.download(url, fname);
return true;
}
}
使用:
(1) 创建目标对象:CDownloader cd = new CDownloader("图片地址","pica.png");
(2) 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
(3) 提交执行:Future<Boolean> result1 = ser.submit(cd);
(4) 获取结果:boolean b = result1.get();
(5) 关闭服务:ser.shutdownNow();
4、静态代理:Runnable接口实现多线程中启动必须借助Thread类对象,Thread类对象就是静态代理。
/**
* 设计模式:静态代理
* 1、真实角色
* 2、代理角色
* 两个角色实现同一个接口
*
*/
public class StaticProxy {
public static void main(String[] args) {
new WeddingCompany(new You()).happyMarry();
//new Thread(线程对象).start();
}
}
interface Marry{
void happyMarry();
}
//真实角色
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("我们结婚了!");
}
}
//代理角色
class WeddingCompany implements Marry{
//真实角色
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void happyMarry() {
ready();
this.target.happyMarry();
after();
}
private void ready() {
System.out.println("布置婚房");
}
private void after() {
System.out.println("闹洞房");
}
}
5、lamda 表达式:避免匿名内部类定义过多、简化线程的使用(用一次)
其实质属于函数式编程的概念
new Thread(()->System.out.println("Lamda")).start();
推导过程:
外部类-->静态内部类-->局部内部类-->匿名内部类-->lambda
lambda推导必须存在类型
6、 线程状态


(1) 进入就绪状态的原因
a、start() b、解除阻塞 c、yield()(运行状态到就绪状态) d、JVM将CPU从本地切换到其他线程
(2) 导致阻塞状态的原因
a、sleep() b、wait() c、join() d、read/write
7、线程方法:
(1)线程停止:
不使用jdk提供的stop()/destroy()方法;
提供一个boolean型的终止变量,当变量为false时停止线程的运行。
(2)sleep()方法 <静态方法>
如果调用了sleep方法后,没有其他等待执行的线程,当前线程不会马上恢复运行。
指定当前线程阻塞的毫秒数;
存在异常InterruptedException;
时间到了后线程进入就绪状态;
可以模拟网络延时、倒计时;
每一个对象都有一个锁,sleep不会释放锁。
(3)join()方法 <对象方法>
合并线程、插队线程
阻塞指定线程等到另一个线程完成以后再继续执行。
(4)yield()方法 <静态方法>
让当前正在执行的线程暂停,不是阻塞线程,而是转入就绪线程;
调用yield后,如果没有其他等待的线程,当前线程就会马上恢复执行。
(5) setDaemon()
可以将指定的线程设置成后台线程,守护线程;
创建用户线程的线程结束时,后台线程也随之消亡;
只能在线程启动前把它设为后台线程。
(6) Priority线程的优先级
setPriority(int newPriority) /getPriority()
线程的优先级代表的是概率,范围从1到10,默认为5。
优先级的设定建议在start()调用前
(7) isAlive() :判断线程是否还活着,线程是否还为终止
(8)setName() 给线程起名、getName 获取线程名字
(9) currentThread() 取得当前正在运行的线程对象
8、线程分类
用户线程:java虚拟机必须等这个线程执行完才会停止
守护线程:java虚拟机不需要等这个线程是否执行完毕
守护线程为用户线程服务

浙公网安备 33010602011771号