Thead 笔记

多线程是异步的,线程被调用的时机是随机的

“当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的”

extends Thread -> implements Runnable

myThread.start() 告知“线程规划器”此线程已准备就绪,等待JVM调用run()方法,表现为异步
如果直接myThread.run() 则变为同步执行,此线程不交给“线程规划器”处理,而是由其所在线程调用myThread线程,也就是必须等到myThread.run()方法执行完毕后才能继续往下执行代码

start()方法的顺序并不代表线程的启动顺序

非线程安全:多个线程对同一个对象的同一个实例变量进行操作时会出现值被更改,值不同步的情况,进而影响程序的执行。
为解决这一问题,可以用synchronized关键字(可加在任意方法及任意类上),被加锁的代码成为互斥区或临界区

interrupted()
1)判断当前线程是否处于停止状态(当前线程是指调用此方法的线程
2)清除线程的停止状态:如果连续两次调用此方法,第二次将返回false
若要停止本身线程,直接写Thread.currentThread().interrupt();
isInterrupted()
判断当前线程是否处于停止状态,但不清除状态标志(也就是说重复调用不会对线程的状态发生改变)
interrupt()
停止线程,但并不是真正的停止线程,只是给线程打上一个停止标志

真正停止线程的方法
1)异常捕获 (推荐理由:将异常向上抛,使线程停止的事件得以传播)
if(thrad.interrrupted){throw new IntrruptedException} … catch(InterruptedException){}
2)在sleep中死亡
3)stop()强制停止(过期方法,不推荐)
4)interrupt() + return

stop() 方法被执行时会抛出ThreadDeath异常,但一般情况下无需显式捕获
stop() 方法可能会使一些清除性的工作得不到完成,另一个情况就是对锁定的对象(被synchronized修饰的对象)进行解锁(对象在执行synchronized 方法过程中被stop()),使数据得不到同步的处理,引起数据不一致,引起程序执行的流程错误,因此不推荐使用

暂停线程
suspend() 暂停执行(过期)
resume() 恢复执行(过期)

有什么缺点呢

  1. 独占
    如果在同步方法(synchronized),或对SynchronizedObject的操作过程中暂停了线程,却没有恢复,那么其他方法将永远也无法获得执行。特别注意,System.out.println()方法,这个方法是同步的。
  2. 不同步

yield() 放弃当前CPU资源

setPriority() 可被继承

Java线程有两种,一种是用户线程,另一种是守护线程
守护线程:典型的守护线程就是GC线程,为所有的非守护线程(用户线程)提供便利服务,当进程中没有非守护线程时,守护
线程自动销毁

方法内的变量是线程安全的(因为非线程安全的问题存在于“实例变量”)

实例变量:一个类内部的私有、保护、公有变量
两个线程访问同一个对象中的同步方法一定是线程安全的

synchronized 同步 排队运行
asynchronized 异步

多线程访问同一个对象,哪个线程先执行带synchronized的方法,哪个线程就先取得该方法所属对象的lock锁

synchronized取得的锁都是对象锁,因此,如果多个线程分别调用多个对象的方法,即使这个方法是带synchronized的,那么这些方法的执行也是异步的,因为synchronized是对象锁,而不是“把某一段代码或方法当作锁”(我的理解就是作用域是对象,而不是创建这个对象的类)

A线程先持有object对象的lock锁,B线程如果在这个时候调用object的synchronized方法,需要等待,也就是同步

但是呢,如果A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object的非synchronized类型的方法

synchronized锁重入
当一个线程获得对象锁后且尚未释放,可以再次请求这个对象锁,并且一定会获得这个对象锁。
如果不可所重入,会造成死锁
可重入锁也支持在父子类继承的环境中

线程执行的代码出现异常时,其持有的锁会自动释放

同步不可以被继承

Thread.sleep

public static native void sleep(long millis)
public static void sleep(long millis, int nanos)

“A native method is a Java method whose implementation is provided by non-java code.”

sleep 是Thread类的静态方法,是让 线程 休眠

Thread.currentThread() 返回当前线程

如果线程是通过继承Thread实现的话这2个方法没有区别

如果线程是通过实现Runnable接口来实现的,则不是Thread类,不能直接使用Thread.sleep()

必须使用Thread.currentThread()来得到当前线程的引用才可以调用sleep(),

Interface Executor

这个对象用来执行提交了的Runnable任务
这个对象通常用来取代原始的创建线程的方式,与其调用new Thread(new RunnableTask()).start();

你可以这样做
Executor executor = getExecutor();
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());

但是Executor不保证线程被异步执行,在最简单的情况下,executor可以在调用者的线程里立即运行提交了的任务
更典型的,提交了的任务将在其他线程中运行,而非调用者的线程,下面的executor将为每个任务创建一个新的线程
class ThreadPerTaskExecutor implements Executor{
public void execute(Runnable r){
new Thread®.start();
}
}

Interface ExecutorService extends Executor

JMM

thread.start 用于启动线程
run 不会启动新的线程

并行
并发

thread类本身实现了runnable接口,并且持有run方法,但run方法是空的,需要子类覆盖
ThreadFactory factory = Executors.defaultThreadFactory();
factory.newThread(Runnable).start();
对于数据竞争,(data race/race condition),应当使用互斥的关键字synchronized来进行互斥处理
如果一个方法使用了synchronized关键字,则该方法在任一时间段内只允许一个线程运行,也称同步方法
每个实例拥有一个独立的锁,我的理解是,synchronized是属于对象的,而不是属于类的,
但若在类的静态代码中使用synchronized,则该静态代码的锁是属于类的

每个实例都拥有一个等待队列
wait() 让线程进入等待队列
myThread.wait() 则称 线程正在myThread上等待
若要执行wait方法,线程必须持有锁,若线程进入等待队列,便会释放其实例锁

notify方法,从等待队列中取出线程
myThread.notify(),myThread的等待队列中的一个线程就会被选中和唤醒,然后退出等待队列

对于共享资源的非线程安全方法,应当使用synchronized关键字
对于加了synchronized的方法,当满足下列条件时,可能出现死锁

死锁的条件

thread 的 start 方法只能被调用一次,如果多次调用,会抛出IllegalThreadStateException
如果直接调用thread的run方法,那么这个线程的run方法实际上是运行在当前线程的,并非运行在其自身线程中(话句话说,就是没有开始一个新的线程)

线程的两种创建方式的区别

  1. 继承Thread 基于继承
  2. 实现runnable接口 基于组合

1.从面向对象的角度看:由于组合的耦合度低于继承,因此用实现runnable的方法更加灵活,所以一般来说优先使用runnable

2.从对象共享的角度看,涉及到竞态和线程安全
3.从对象创建成本的角度看,JVM 在创建Thread时会为其分配调用栈空间,内核线程资源等,成本相对于普通runnable实例要高

守护线程daemon thread 和用户线程 user thread
用户线程会阻止JVM的正常停止,即JVM会在所有用户线程接受后才能结束
守护线程不影响JVM的正常停止,守护线程一般用于执行重要性不高的任务,如监视其他线程的运行情况
若JVM被强制停止(System.exit),那么即使是用户线程也无法阻止JVM的停止

jion 等待线程运行结束
若在A线程中调用B线程的jion方法,则A线程会暂停,直到B运行结束

yield 放弃对处理器的占用,可能会导致当前线程被暂停
该方法不可靠,即被调用后当前线程仍可能继续运行

sleep 使当前线程休眠(暂停运行)

Java 线程状态
Thread.getState()

NEW 已创建但未启动
RUNNABLE 复合状态
READY 等待被线程调度器调度 ,此时称之为活跃线程
RUNNING 处理器正在执行其run方法
通过执行yield 方法,其状态可能由RUNNING转化为READY
BLOCKED 不会占用处理器资源,当阻塞式I/O操作完成后

WAITING object.wait() Thread.join()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值