2020-11-2多线程笔记整理

1. 多线程技术概述
1.1进程:
一个内存运行中的应用程序,每一个进程都有一个空间。
1.2线程:
是进程的一个执行路劲,共享一个内存空间,线程之间可以自由切换,并发执行,同时,一个进程最少有一个线程。
线程实际上是进程基础之上的进一步的划分,一个进程启动之后,里面若干执行路径又可以分为若干的线程。

2.线程的调度
线程的调度分为分时调度和抢占式调度,java使用的是抢占式调度。
2.1分时调度:
所有线程轮流使用CPU,使用的时间平均分配。
2.2抢占式调度:
优先让优先度较高的线程使用CPU,若优先级相同,则随机调度一个线程,

:CPU在某一时刻只能执行一个线程,但是,因为CPU的切换线程的速度相当快,快到人无法感知,所以感觉线程是同时进行的,但其实并不是,人脑可以想很多东西,但是并不是同时想的,是一个一个来的,CPU类似于人脑,也得一个个操作,只是CPU切换快,所以感觉不到他切换。

小问题:
问: 让1000个线程同时让CPU进行操作和让1000个线程排队进行操作,哪个占用的时间多?
答: 前者占用的时间多,因为后者是排队进行操作的,一个执行完了,立马执行下一个,而如果让CPU同时进行操作,则会每个线程做一点,就花时间去做下一个,每个做一点就换下一个,虽然切换的够快,但是,还是会消耗时间,放大来看的话,前者耗时会更高一些,因此说明, 多线程不能提高运行速度,但能提高效率。

多线程操作:Thread
线程执行任务的方法:run方法
线程的执行顺序:
1.程序启动 --> main线程开启(main是主线程) -->main方法执行 -->创建m线程 -->进行操作 -->结束后关闭
2.程序启动 --> main线程开启(main是主线程) -->main方法执行 -->创建m线程 -->m线程开启 -->进行操作 --> 结束后关闭

子线程中的方法只在子线程中执行
每个线程都有自己的栈空间,共用一份栈内存

Runnable接口
1.创建任务对象

MyRunnable r = new MyRunnable();//MyRunnable是继承了Runnable的方法.

2.创建线程,分配任务

Thread t = new Thread(r);

使用Runnable接口的优势

  1. 创建任务,由线程进行分配
  2. 避免单继承的局限性//Java采用的是单继承的模式
  3. 任务抢占线程是分离的
  4. 后期线程池不接受Thread,但是接受Runnable;

Thread 类

  1. 通过变量进行标记,来停止线程,早先的.stop已经停用了
  2. .sleep 休眠,让进程暂时停止执行
  3. .deamon 守护线程,用于守护用户线程,用户线程完全结束,进程才/就结束

线程安全问题:
线程安全 <–> 同步操作,线程排队进行操作,效率低
线程不安全 <–> 异步操作,线程同时进行,效率较高,但容易出现问题。
线程不安全:由于线程是同时进行的,一个还没完成,下一个就已经在做了,会导致数据上一刻还是正确的,下一刻马上就被改动了,系统上一刻判断能正常进行操作,下一刻里面就不能操作了,但是系统还是操作了,就会出现问题,就好比于几个人去买票,几个窗口都有卖,就剩最后一张的时候,几个窗口是共有最后一张票的,几个人同时买票,卖票的也同时操作了,钱都付完了,但是,票只剩一张,几个人都付钱了,还是不能退钱的那种,肯定会出现问题的。

并发与并行
并发:两个或多个事件在同一时间段内发生
并行:两个或多个事件在同一时刻 发生(是同时进行的)

获取和设置线程名称

Thread.currentThread().getName();//若没有指定线程名称,名称为:Thread-数字,数字从0开始;

线程休眠

Thread.sleep(1000); //括号里面的单位是毫秒,1s = 1000ms;

线程阻塞:
包括休眠,读文件等一些列比较消耗时间的操作,都是线程阻塞

线程中断
由线程自己决定是否要中断,最好不要认为掐死,不然会造成无法释放的垃圾,可以通过中断标记,触发异常,来决定是否关闭,如果,线程还没执行完毕,就砍死,会造成回收器无法回收的垃圾。
线程中断异常:InterruptedException

守护线程:用于守护用户线程的,当最后一个用户线程死亡,所有的守护线程死亡,
用户线程:当一个进程不含任何存活的用户线程时,结束。
设置守护线程:

t1.setDaemon

线程安全问题:
出现不合理的问题,在前一进程结束前,另一个直接调用,会造成不该出现的结果。

注: 在java中,隐式锁都是不公平锁。
同步代码块: synchronized
通过同步代码块打标注的内容,会进行排队。
格式:

synchronized(锁对象) {}

若有锁标记,会进行等待,执行完毕后,解锁;然后,其他没执行的线程进行抢锁,抢到了,在调用锁来锁住,用完了继续解锁。

只有等待同一把锁才能进行排队(在同一个门口等待才要进行等待,厕所门很多的时候,没必要死在同一个坑里面。)

同步方法: 力度比较细,方法返回值前加synchronized

public synchronized void baby() {}

如果同步代码块锁了,同步方法也锁了,因为看着同一个锁,“大门” 都得排队。*注:*虽然里面有坑位,但是,厕所外面的门得排队进,里面人不出来,别想进去。

显示锁:Lock
自己配锁,自己锁
学习时,注意子类:“ReentrantLock”可以决定该显示锁是不是公平锁;

ReentrantLock(true//若为true,就是公平锁,为false是不公平锁.

使用锁:

Look l = new ReentrantLock(true);
l.look();//锁住
l.unlook();//解锁

使用显示锁较隐式锁更能体现面向对象的机制。

公平锁于不公平锁
公平锁:先到先得,有排队的流程
不公平锁:谁抢到,锁归谁。不讲先到先得

线程死锁:
通俗理解:顾客想花少的钱,吃多的东西,老板想顾客多花钱,少吃东西,两个都这么想,一个等对面多掏钱,另一个等对面先降价,就死犟。
解决方法:在任何有可能产生锁的方法中,不在调用另一个方法产生锁

多线程的通信问题:
A买了包子,B才能有包子吃。A买回来了,告诉B来吃。而不是,A包子还没买,B就吃完了(合法公民不做强盗)。
方法:

.notify();//随机唤醒一个线程
.notifyAll();//全部唤醒
.wait(); //等待唤醒

线程的六种状态:
New:刚创建,还没有使用的状态.。
Runnable:执行状态
Blocked:被阻塞,等待锁(排队中)
Waiting:等待中。。。(一直等待唤醒,在休眠中)
TimedWaiting:计时等待中,时间到就醒
Terminated:结束了,退出

Callable:待返回值的线程
使用步骤:

//1.编写Callable接口,实现call方法
Class xxx implements Callable<T> {
	@override
	public<T> call() throws Exception {
	 return T;
	 }
}

//2.创建FutureTask对象,病传入第一步写的Callable类对象
FutureTask<Integer> ft = new FutureTask<> (callable);

//3.通过Thread,启动线程
new Thread(ft).start();

方法:
get(); 获取线程调用方法,需要等待计算完成,然后检索结果.
get(long timeout, TimeUnit unit); 超时就不要结果了

线程池部分在抽时间整理.
2020-11-02

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值