Java学习——线程

线程:线程(Thread)是控制线程(Thread of Control)的缩写,它是具有一定顺序的指令序列(即所编写的程序代码)、存放方法中定义局部变量的栈和一些共享数据。线程是相互独立的,每个方法的局部变量和其他线程的局部变量是分开的,因此,任何线程都不能访问除自身之外的其他线程的局部变量。如果两个线程同时访问同一个方法,那每个线程将各自得到此方法的一个拷贝。

Java中线程的实现通常有两种方法:对Thread类进行派生并覆盖run方法(继承Thread类并覆盖Thread类的run方法完成线程类的声明);另一种是通过实现Runnable接口

1、派生Thread类并重载run方法




多线程:



程序运行结果:


2、实现Runable接口创建线程:

单线程:



多线程:


程序运行结果:


线程生命周期:

线程的4种状态:线程创建、可运行状态、不可运行状态、退出

创建(new)状态:调用new方法产生一个线程对象后、调用start方法前所处的状态。还没有调用 start方法是无法启动的,也无法执行。当线程处于创建状态时,线程对象可以调用start方法进入启动状态,也可以调用stop方法进入停止状态。

可运行(runnable)状态:当线程对象执行start()方法后,线程就转到可运行状态。进入些状态只是说明线程对象具有了可以运行的条件,但线程并不一定处于运行状态。因为在单处理器系统中运行多线程程序时,一个时间点只有一个线程运行,系统通过调试机制实现宏观意义上的运行线程共享处理器。因此一个线程是否在运行,除了它必须处于Runnable状态之外,还取决于优先级和调试。

不可运行(non Runnable)状态:线程处于不可运行状态 是由于线程被挂起或者发生阻塞,例如对一个线程调用wait()函数后,它就进入阻塞状态;调用线程的notify或notifyAll方法后它才能再次回到可执行状态。

v退出(done)状态 :一个线程可以从任何一个状态中调用stop方法进入退出状态。

线程一旦进入退出状态就不存在了,不能再返回到其他的状态。除些之外,如果线程执行完run方法,也会自动进入退出状态。



线程的创建和启动:

Java利用Thread来创建线程,通过线程类的构造方法创建一个线程,并通过调用start方法启动该线程,启动线程的目的是为了执行它的run()方法,而Thread类中默认的run()方法没有任何可操作代码,所以必须重新定义run()方法。java通过两种重新定义run()方法的方式:

1、派生线程类Thread的子类

2、实现Runnable的接口


线程在调用start()方法之后,系统会自动调用run()方法。start()方法被调用之后,系统会得知线程准备完毕并且可以执行run()方法,start()方法就返回了,start()方法不会等待run()方法执行完毕。

线程状态转化:

1、以下几种情况发生时,线程进入可执行状态:

(1)其他线程调用notify()或者notifyAll()方法,唤起处于不可执行状态的线程。

public final void notify()  //仅仅唤醒一个线程并允许它获得锁

public final void notifyAll() //唤醒所有等待这个对象的线程,并允许它们获得锁

wait和notify是Java同步机制的重要内容。

(2)线程调用sleep(millis)方法,millis毫秒之后线程会进入可执行状态,在millis毫秒内让当前正在执行的线程进入休眠状态,时间到了后自动苏醒并继续执行。

static void sleep(long millis,int nanos(纳秒)) throws InterruptedException

(3)线程对I/O操作的完成

2、以下情况线程进入不可执行状态

(1)线程自动调用wait()方法,等待某种条件的发生

public final void wait() throws InterruptedException

(2)线程调用 sleep()方法进入不可执行状态,在一定时间后会进入可执行状态。

(3)线程等待I/O操作的完成



等待线程结束:

isAlive()方法用来判断一个线程是否存活。

1、当线程处于可执行状态 或者 不可执行状态 时,isAlive()方法返回true;

2、当线程处于创建状态或者退出状态时,则返回false

public final boolean isAlive() //该方法用于测试线程是否处于活动状态(已启动调用 了start方法,且尚未退出所处的状态)

如何判断一个线程是否已经终止??

(1)不断查询 第一个线程是否已经终止,如果没有,则让主线程睡眠一直到它终止即“while/isAlive/sleep”

线程1.start();

while(线程1.isAlive()){

    Thread.sleep(休眠时间);

}

线程2.start();

(2)利用join()方法

public final void join(long millis,int nanos) throws InterruptedException

等待该线程终止的时间最长为毫秒(millis)加纳秒(nanos),为0时表示一直等待下去

public final void join() throws InterruptedException

等待该线程终止



Mthod2()



这一次为什么没有等th1结束等1s再执行th2呢?

线程调度:

多线程应用程序的每一个线程的重要性和优先级可能不同。多个线程都在等待获得CPU的时间片,优先级高的线程能抢占CPU并得以执行;当多个线程交替抢占CPU时,优先级高的线程占用的时间应该多。

Java中CPU的使用通常是抢占式调试模式(是指多线程处于可运行状态,但只有一个线程正在运行,当线程一直运行直到结束,或者进入不可运行状态,或者具有更高优先级的线程变为可运行状态,它将会让出CPU)不需要时间片分配 里程。

设置线程优先级:public final void setPriority(int newPriority)

newPriority的值必须在MIN_PRIORITY到MAX_PRIORITY范围内,通常它们的值分别1和10.目前Windwos系统只支持3个级别的优先级,它们分别是Tread.MAX_PRIORITY、Thread.MIN_PRIORITY和Thread.NORM_PRIOPRITY

获取当前线程优先级:public final int getPriority()



改变优先级:




线程同步:

在线程异步模式的情况下,同一时刻有一个线程在修改共享数据,另一个线程在读取共享数据,当修改共享数据的线程没有处理完毕,读取数据的线程肯定会得到 错误的结果。如果采用多线程的同步控制机制,当处理共享数据的线程完成 处理数据之后,读取线程读取数据。

异步模式的例子:



上面由于线程不同步导致的错误,Java引入了“锁”的机制。

锁:每个线程进入共享代码之前获得锁。否则不能进入共享代码区,并且在退出共享代码之前释放该锁,这样就能达到线程同步的目的。

关键字:synchronized声明的方法为同步方法。Java有一个专门负责管理线程对象中同步方法访问的工具——同步模型监视器,它的原理是为每个具有同步代码的对象准备一把惟一的“锁”。当多个线程访问对象时,只有取得锁的线程才能进入同步 方法,其他访问共享对象的线程停留在对象中等待,如果获得锁的线程调用 wait方法放弃锁,那么其他 等待的线程将有机会获得锁。当某个等待线程取得 锁,它将执行同步 方法,而其他没有取得 锁的线程仍然继续等待获得锁。

Java中线程之间通过 消息实现相互通信,wait()、notify()及notifyAll()方法可完成线程间的消息传递。

如:一个对象包含一个synchonized同步方法,同一时刻只能有一个获得锁的线程访问该对象中的同步 方法,其他 线程被阻塞在对象 中等待获得锁。当线程调用 wait()方法可使该线程进入 阻塞状态,其他线程调用notify()或notifyAll()方法可以唤醒该线程。



死锁:由于两个线程都 在等待对方释放各自拥有的锁的现象称为死锁。这种现象往往是由于相互嵌套的synchronized代码段而造成,因此,在程序中尽量少用嵌套的synchronized代码块。

线程通信:Java中线程之间的通信是通过Object类中的wait()、notify()、notifyAll()等几种方法实现的。Java中每个对象内部不仅有一个对象锁之外,还有一个线程等待队列,这个队列用于存放所有等待对象锁的线程。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值