在Java中创建线程有两种方法:使用Thread类和使用Runnable接口。
要注意的是Thread类也实现了Runnable接口,因此,从Thread类继承的类的实例也可以作为target传入这个构造方法。可通过这种方法实现多个线程的资源共享。
线程的生命周期:
1.新建状态(New):用new语句创建的线程对象处于新建状态,此时它和其它的java对象一样,仅仅在堆中被分配了内存
2.就绪状态(Runnable):当一个线程创建了以后,其他的线程调用了它的start()方法,该线程就进入了就绪状态。处于这个状态的 线程位于可运行池中,等待获得CPU的使用权
3.运行状态(Running): 处于这个状态的线程占用CPU,执行程序的代码
4.阻塞状态(Blocked): 当线程处于阻塞状态时,java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才有机会转到 运行状态。
阻塞状态分为三种情况:
1)、 位于对象等待池中的阻塞状态:当线程运行时,如果执行了某个对象的wait()方法,java虚拟机就回把线程放到这个对象的等待池中
2)、 位于对象锁中的阻塞状态,当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他的线程占用,JVM就会把这个线程放到这个对象的琐池中。
3)、 其它的阻塞状态:当前线程执行了sleep()方法,或者调用了其它线程的join()方法,或者发出了I/O请求时,就会进入这个状态中。
一、创建并运行线程
当调用start方法后,线程开始执行run方法中的代码。线程进入运行状态。可以通过Thread类的isAlive方法来判断线程是否处于运行状 态。当线程处于运行状态时,isAlive返回true,当isAlive返回false时,可能线程处于等待状态,也可能处于停止状态。
二、挂起和唤醒线程
一但线程开始执行run方法,就会一直到这个run方法执行完成这个线程才退出。但在线程执行的过程中,可以通过两个方法使线程暂时停止执行。这两个方 法是suspend和sleep。在使用suspend挂起线程后,可以通过resume方法唤醒线程。而使用sleep使线程休眠后,只能在设定的时间 后使线程处于就绪状态(在线程休眠结束后,线程不一定会马上执行,只是进入了就绪状态,等待着系统进行调度)。
虽然 suspend和resume可以很方便地使线程挂起和唤醒,但由于使用这两个方法可能会造成一些不可预料的事情发生,因此,这两个方法被标识为 deprecated(弃用)标记,这表明在以后的jdk版本中这两个方法可能被删除,所以尽量不要使用这两个方法来操作线程。
三、终止线程的三种方法
有三种方法可以使终止线程。
1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
2. 使用stop方法强行终止线程(线程中调用了阻塞代码)(这个方法不推荐使用,因为stop是依靠抛出异常来结束线程的,也可能发生不可预料的结果)。如果没有调用阻塞代码,可以正常结束线程。
3. 使用interrupt方法中断线程(线程中调用了阻塞代码)(其实这种方法也是通过抛出异常来结束线程的)。如果没有调用阻塞代码,可以通过判断线程的中断标志位来介绍线程。
线程的几个方法:
join():等待此线程死亡后再继续,可使异步线程变为同步线程
interrupt():中断线程,被中断线程会抛InterruptedException
wait():等待获取锁:表示等待获取某个锁执行了该方法的线程释放对象的锁,JVM会把该线程放到对象的等待池中。该线程等待其它线程唤醒
notify():执行该方法的线程唤醒在对象的等待池中等待的一个线程,JVM从对象的等待池中随机选择一个线程,把它转到对象的锁池中。使线程由阻塞队列进入就绪状态
sleep():让当前正在执行的线程休眠,有一个用法可以代替yield函数——sleep(0)
yield():暂停当前正在执行的线程对象,并执行其他线程。也就是交出CPU一段时间(其他同样的优先级或者更高优先级的线程可以获取到运行的机会)
sleep和yield区别:
1、sleep()方法会给其他线程运行的机会,而不考虑其他线程的优先级,因此会给较低线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。
2、当线程执行了sleep(long millis)方法后,将转到阻塞状态,参数millis指定睡眠时间;当线程执行了yield()方法后,将转到就绪状态。
3、sleep()方法声明抛出InterruptedException异常,而yield()方法没有声明抛出任何异常
4、sleep()方法比yield()方法具有更好的移植性
如果希望明确地让一个线程给另外一个线程运行的机会,可以采取以下的办法之一:
1、调整各个线程的优先级
2、让处于运行状态的线程调用Thread.sleep()方法
3、让处于运行状态的线程调用Thread.yield()方法
4、让处于运行状态的线程调用另一个线程的join()方法
首先,wait()和notify(),notifyAll()是Object类的方法,sleep()和yield()是Thread类的方法。
(1).常用的wait方法有wait()和wait(long timeout):
void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
void wait(long timeout) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。
wait()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized代码块中进 行调用。如果在non- synchronized函数或non-synchronized代码块中进行调用,虽然能编译通过,但在运 行时会发生IllegalMonitorStateException的异常。
(2).Thread.sleep(long millis),必须带有一个时间参数。
sleep(long)使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行;
sleep(long)可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;
sleep(long)是不会释放锁标志的。
(3).yield()没有参数。
sleep 方法使当前运行中的线程睡眼一段时间,进入不可运行状态,这段时间的长短是由程序设定的,yield 方法使当前线程让出CPU占有权,但让出的时间是不可设定的。yield()也不会释放锁标志。
实际上,yield()方法对应了如下操作: 先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把 CPU 的占有权交给此线程,否则继续运行原来的线程。所以yield()方法称为“退让”,它把运行机会让给了同等优先级的其他线程。
sleep方法允许较低优先级的线程获得运行机会,但yield()方法执行时,当前线程仍处在可运行状态,所以不可能让出较低优先级的线程些时获得 CPU占有权。 在一个运行系统中,如果较高优先级的线程没有调用 sleep 方法,又没有受到 I/O阻塞,那么较低优先级线程只能等待所有较高优先级的线程运行结束,才有机会运行。
yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。所以yield()只能使同优先级的线程有执行的机会。
volitile 语义
volatile相当于synchronized的弱实现,也就是说volatile实现了类似synchronized的语义,却又没有锁机制。它确保对volatile字段的更新以可预见的方式告知其他的线程。
volatile包含以下语义:
(1)Java 存储模型不会对valatile指令的操作进行重排序:这个保证对volatile变量的操作时按照指令的出现顺序执行的。
(2)volatile变量不会被缓存在寄存器中(只有拥有线程可见)或者其他对CPU不可见的地方,每次总是从主存中读取volatile变量的结 果。也就是说对于volatile变量的修改,其它线程总是可见的,并且不是使用自己线程栈内部的变量。也就是在happens-before法则中,对 一个valatile变量的写操作后,其后的任何读操作理解可见此写操作的结果。
尽管volatile变量的特性不错,但是volatile并不能保证线程安全的,也就是说volatile字段的操作不是原子性的,volatile变量只能保证可见性(一个线程修改后其它线程能够理解看到此变化后的结果),要想保证原子性,目前为止只能加锁!
数据同步:
线程同步的特征:
1、如果一个同步代码块和非同步代码块同时操作共享资源,仍然会造成对共享资源的竞争。因为当一个线程执行一个对象的同步代码块时,其他的线程仍然可以 执行对象的非同步代码块。(所谓的线程之间保持同步,是指不同的线程在执行同一个对象的同步代码块时,因为要获得对象的同步锁而互相牵制)
2、每个对象都有唯一的同步锁
3、在静态方法前面可以使用synchronized修饰符,但是要注意的是锁对象是类(用Object.class而不能用this),而不是这个类的对象。
4、当一个线程开始执行同步代码块时,并不意味着必须以不间断的方式运行,进入同步代码块的线程可以执行Thread.sleep()或者执行Thread.yield()方法,此时它并不释放对象锁,只是把运行的机会让给其他的线程。
5、synchronized声明不会被继承,如果一个用synchronized修饰的方法被子类覆盖,那么子类中这个方法不在保持同步,除非用synchronized修饰。
6、synchronized 关键字能够修饰一个对象实例中的函数或者代码块。 在一个非静态方法中 this 关键字表示当前的实例对象。 在一个 synchronized 修饰的静态的方法中,这个方法所在的类使用 Class 作为实例对象
相关推荐
Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...
#### 一、Java线程:概念与原理 - **操作系统中线程和进程的概念** 当前的操作系统通常都是多任务操作系统,多线程是一种实现多任务的方式之一。在操作系统层面,进程指的是内存中运行的应用程序,每个进程拥有...
#### 一、Java线程:概念与原理 1. **操作系统中线程和进程的概念** - 当前的操作系统通常为多任务操作系统,多线程是实现多任务的一种手段。 - **进程**:指内存中运行的应用程序,每个进程拥有独立的内存空间。...
Java多线程是Java编程中的一个核心概念,它在现代软件开发中扮演着至关重要的角色。多线程允许程序同时执行多个任务,提高了系统资源的利用率,提升了应用程序的响应速度和并发性能。对于大型分布式系统、Web应用...
Java中实现多线程主要有两种方式:继承Thread类和实现Runnable接口。 ### 继承Thread类 在Java中,通过继承`Thread`类并重写其`run()`方法可以创建自定义线程。`Thread`类是Java提供的一个基础类,用于封装线程的...
创建Java线程主要有两种方式: 1. 扩展`java.lang.Thread`类。通过重写`run()`方法来定义线程的行为。当调用`start()`方法时,会启动一个新的线程并执行`run()`方法。 2. 实现`java.lang.Runnable`接口。在实现类的`...
在Java中,线程并发可以通过多种方式实现,包括继承Thread类、实现Runnable接口以及使用ExecutorService和Future等高级API。下面将详细探讨这些知识点。 首先,Java中创建线程主要有两种方法。一种是通过继承Thread...
Java线程有10个优先级(MIN_PRIORITY, NORM_PRIORITY, MAX_PRIORITY),默认优先级是NORM_PRIORITY。但是,线程优先级并不保证绝对的执行顺序,操作系统调度策略可能影响实际执行顺序。 7. join()方法: 一个线程...
在Java编程中,多线程是一项关键特性,它允许程序同时执行多个任务,提升系统效率。在处理耗时操作如大文件下载、数据处理或网络请求时,展示进度条能够提供用户友好的交互体验,让使用者了解任务的完成状态。本主题...
创建Java线程有两种主要方式: 1. 继承`java.lang.Thread`类,重写`run()`方法,并通过`start()`方法启动线程。 2. 实现`Runnable`接口,提供`run()`方法,然后将`Runnable`实例传递给`Thread`类的构造函数来创建...
Java线程有10个优先级,从MIN_PRIORITY(1)到MAX_PRIORITY(10),默认优先级是NORM_PRIORITY(5)。线程优先级并不保证执行顺序,但高优先级的线程更有可能获得CPU资源。 4. **线程的休眠与唤醒**: - `Thread....
**一、Java线程:概念与原理** 1. **线程与进程**: - **进程**:是操作系统资源分配的基本单位,每个进程都有独立的内存空间。 - **线程**:是进程中的一个执行流,线程间共享进程的内存空间。在Java中,每个...
4. **线程状态**:Java线程有五种状态:新建、可运行、运行、阻塞和死亡。了解这些状态可以帮助开发者更好地控制和调试线程。 5. **线程优先级**:每个线程都有一个优先级,Java中从1(`MIN_PRIORITY`)到10(`MAX_...
本文将深入探讨Java线程的核心概念、API以及在实际开发中的应用,旨在帮助你理解和掌握这一关键技能。 首先,我们需要了解什么是线程。在单核CPU系统中,线程是操作系统调度的基本单位,而在多核CPU系统中,每个...
在Java中,实现多线程有两种主要方式:通过实现Runnable接口或者继承Thread类。本案例将深入探讨Java多线程中的关键知识点,包括线程同步、线程通信和线程阻塞。 线程同步是为了防止多个线程同时访问共享资源,导致...
Java多线程是Java编程中的重要概念,尤其在如今的多核处理器环境下,理解并熟练掌握多线程技术对于提高程序性能和响应速度至关重要。本资料详细讲解了Java多线程的原理,并提供了丰富的实战代码,非常适合Java初学者...
在“Java多线程学习总结6”这个主题中,我们可以深入探讨Java多线程的实现、管理及优化。下面将详细阐述相关知识点。 1. **线程的创建方式** - **继承Thread类**:自定义类继承Thread类,并重写run()方法,创建...