Java入门第十弹

多任务处理有两种不同的类型:
一、基于进程的:
进程(process)本质上说一个执行的程序。因此,基于进程的多任务处理的特点是允许你的计算机同时运行两个或更多的程序。
eg:你在运用文本编辑器的时候可以同时运行java编译器。在基于进程的多任务处理中,程序是调度所分配的最小代码单位。

二、基于线程的:
在基于线程的多任务处理环境中,线程是最小的执行单位。这意味着一个程序可以同时执行两个或者多个任务的功能。
eg:一个文本编辑器可以在打印的同时格式化文本。

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,
一个运行的exe就是一个进程。进程是重量级的任务;需要分配它们自己独立的地址空间。

线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,
进程中的多个线程共享进程的内存。线程是轻量级的任务;它们共享相同的地址空间并且共享同一个进程。

问:程序、进程和线程有什么区别?

问:创建线程有几种方式?
如何创建线程:
方法一:
1创建一个类T实现Runnable接口,覆盖其中的run()(线程运行的代码)。
2以类T的对象t作为创建Thread类对象的构造函数的参数。Thread th=new Thread(t);
3调用start()启动线程。th.start();
注意:不是用run()启动线程.启动线呈并不是立即执行run(),启动和执行是两回事.
方法二:
创建一个类继承Thread类,覆盖其中的run()。

主线程:所有java程序都有线程,当java程序启动时,一个线程立刻运行,该线程通常叫做程序的主线程。
主函数本身就是一个线程,也就是主线程。
主线程的重要性体现在两方面:
1它是产生其他子线程的线程。
2通常它是最后完成执行。

线程的生命周期:
1、新生状态NewBorn:新创建了一个线程对象。
2、就绪状态Runnable:线程对象调用start()方法,该状态的线程位于可运行线程池中,等待获取CPU的使用权
3、死亡状态Dead:线程执行完了或者因异常退出了run()方法,该线程结束生命周期。线程一旦死亡,就不能复生。 如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。

4、阻塞状态Pause:阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

阻塞的情况分三种:
(一)等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态
实际上这个三状态组合为一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。

线程常用方法:
start(); newBorn—–>Runnable
yield(); running—–>ready
Thread.sleep(); running—–>pause 使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
jion(1000); jion();等待调用该方法的线程执行完毕后再往下继续执行。实现同步

Join方法实现是通过wait(Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程。
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
notityAll():唤醒所有处于等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

小结:
Thread.yield()方法作用是:
暂停当前正在执行的线程对象,并执行其他线程。
yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

Thread.sleep()方法的作用:
1、线程睡眠是帮助所有线程获得运行机会的最好方法。
2、线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态。sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。
3、sleep()是静态方法,只能控制当前正在运行的线程。
创建多线程:
多个线程共享一个cpu,而cpu在点时刻只能执行一条指令(也就是只能运行一个线程),所以线程之间是切换运行的。如何切换与OS有关。
线程之间切换运行的方式:
1优先级:
2时间片轮换:
3优先级+时间片轮换

同步问题提出: 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。

线程同步实现方法:分别是synchronized、wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
notityAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
注意:
wait()、notify()、notityAll()方法是普通对象的方法(Object超类中实现),而不是线程对象的方法
wait()、notify()、notityAll()方法只能在同步方法中调用

实现同步的方式
同步是多线程中的重要概念。同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果。同步的实现方式有两种,同步方法和同步块,这两种方式都要用到synchronized关键字。

给一个方法增加synchronized修饰符之后就可以使它成为同步方法,这个方法可以是静态方法和非静态方法,
但是不能是抽象类的抽象方法,也不能是接口中的接口方法。

synchronized(this){}
synchronized void f(){}

线程在执行同步方法时是具有排它性的。当任意一个线程进入到一个对象的任意一个同步方法时,这个对象的所有同步方法都被锁定了,在此期间,其他任何线程都不能访问这个对象的任意一个同步方法,直到这个线程执行完它所调用的同步方法并从中退出,从而导致它释放了该对象的同步锁之后。在一个对象被某个线程锁定之后,其他线程是可以访问这个对象的所有非同步方法的。

同步块是通过锁定一个指定的对象,来对同步块中包含的代码进行同步;
同步方法是对这个方法块里的代码进行同步,而这种情况下锁定的对象就是同步方法所属的主体对象自身。

如果这个方法是静态同步方法呢?那么线程锁定的就不是这个类的对象了,也不是这个类自身,而是这个类对应的java.lang.Class类型的对象。同步方法和同步块之间的相互制约只限于同一个对象之间,所以静态同步方法只受它所属类的其它静态同步方法的制约,而跟这个类的实例(对象)没有关系。

java中的嵌套同步是安全的。
synchronized(a)
{
f();
}
public void f()
{
synchronized(a){}
}

死锁:死锁发生在两个线程对一对同步对象有循环依赖关系时,所以线程过多的使用同步可能造成死锁。

synchronized(a)
{
synchronized(b){}
}

sybchronized(b)
{
synchronized(a){}
}

一些常见问题?
1、线程的名字,一个运行中的线程总是有名字的,名字有两个来源,一个是虚拟机自己给的名字,一个是你自己的定的名字。在没有指定线程名字的情况下,虚拟机总会为线程指定名字,并且主线程的名字总是mian,非主线程的名字不确定。
2、线程都可以设置名字,也可以获取线程的名字,连主线程也不例外。
3、获取当前线程的对象的方法是:Thread.currentThread();
4、在上面的代码中,只能保证:每个线程都将启动,每个线程都将运行直到完成。一系列线程以某种顺序启动并不意味着将按该顺序执行。对于任何一组启动的线程来说,调度程序不能保证其执行次序,持续时间也无法保证。
5、当线程目标run()方法结束时该线程完成。
6、一旦线程启动,它就永远不能再重新启动。只有一个新的线程可以被启动,并且只能一次。一个可运行的线程或死线程可以被重新启动。
7、线程的调度是JVM的一部分,在一个CPU的机器上上,实际上一次只能运行一个线程。一次只有一个线程栈执行。JVM线程调度程序决定实际运行哪个处于可运行状态的线程。
众多可运行线程中的某一个会被选中做为当前线程。可运行线程被选择运行的顺序是没有保障的。
8、尽管通常采用队列形式,但这是没有保障的。队列形式是指当一个线程完成“一轮”时,它移到可运行队列的尾部等待,直到它最终排队到该队列的前端为止,它才能被再次选中。事实上,我们把它称为可运行池而不是一个可运行队列,目的是帮助认识线程并不都是以某种有保障的顺序排列唱呢个一个队列的事实。
9、尽管我们没有无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值