在说线程之前,有必要说下线程与进程之间的关系。
附oracle官网链接:https://docs.oracle.com/javase/tutorial/essential/concurrency/procthread.html
这里有原版的关于线程和进程的介绍,我们只简单介绍下,作为知识普及。
一.进程与线程的关系
1.进程:进程一般情况下是程序或者应用程序的同义词,是系统进行资源和调度的基本单位,是操作系统结构的基础。它有自己独立的内存空间,换句话说,它有一套私有的运行时资源。在现代面向线程的计算机结构中,进程作为了线程的容器存在,而进程变为了程序的代名词。但是要注意的是,Java虚拟机的大多数实现都是作为一个进程运行的。
2.线程:在面向线程的计算机结构中,线程有时被称为轻量级的进程。在进程中,各个线程共享进程的资源(内存和文件)。每个应用程序都至少包含一个线程。
3.为什么要使用线程进行并发程序设计?
因为相对于进程来说,线程的切换和调度的成本远远小于进程。
二.线程的生命周期
既然要说线程,就免不了说下线程的生命周期,也就是各个状态之间的转换。



可以看到,在源码Thread类中定义了一个枚举类型State,这个State就是线程生命周期中的各种状态。
根据英文注释,我们可以知道各个状态的含义,这里不细说。
附线程的状态转换图:

后续篇我们逐渐详述介绍这几种状态之间的转换过程。
三.线程的基本操作(这些都很简单,不在这里详细说)
1.新建线程
新建一个线程有两种方式:一种是继承Thread类,并重写Thread类的run方法(因为你要在run方法中实现你的业务逻辑);另外一种是实现Runnable接口。
public class ThreadDemo extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
System.out.println("继承Thread实现线程执行");
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
new ThreadDemo().start();
}
}
public class RunnableDemo implements Runnable {
@Override
public void run() {
System.out.println("我的第一个线程程序!");
}
public static void main(String[] args) {
new Thread(new RunnableDemo()).start();
}
}
其实通过源码来看,实际就是一种方式,直接实现Runnable接口。我们可以看下Thread源码类中:
所以关于如何新建线程的方式的讨论可以休矣。
2.废弃方法(可以不看了)
stop方法:暴力终止,会出现数据不一致,废弃也在情理之中,被带有中断机制的方法代替了。
suspend:挂起方法,也被废弃了,是因为调用此方法后,线程挂起后不释放资源,并且线程的状态是RUNNABLE,可能会让我们误判当前的系统状态。
resume:是与suspend配套使用的,但是如果它比suspend先执行,那线程永远挂着了,图就不截了。
3.中断方法:
有关中断的有三个方法:
①Thread类中的interrupt()方法是实例方法,它可以设置线程的中断标识(也就是说并不是调用这个方法就中断了)
②配合Thread类中的实例方法isInterrupted()来判断当前调用线程是否设置了中断标识。
③Thread类中的interrupted()也是用来判断当前的中断状态,但是会清除中断标识位。
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
@Override
public void run() {
while(true){
System.out.println(Thread.currentThread().interrupted());
if(Thread.currentThread().isInterrupted()){
System.out.println("我被中断了!");
break;
}
}
}
};
t.start();
t.interrupt();
}
另外要注意的是,使用Thread.sleep(long xx)方法时(还有join方法,凡是报中断异常的方法),如果线程被中断,会抛出中断异常,并且标志位也会被清除。
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
@Override
public void run() {
while(true){
try {
System.out.println(Thread.currentThread().getName()+"|"+Thread.currentThread().isInterrupted());
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"|"+Thread.currentThread().isInterrupted());
} catch (InterruptedException e) {
e.printStackTrace();
//如果要正确处理逻辑,这里要恢复中断标志位,重新进行中断
//重新设置中断标志
Thread.currentThread().interrupt();
}
if(Thread.currentThread().isInterrupted()){
System.out.println("我被中断了!");
break;
}
}
}
};
t.start();
t.interrupt();
}
4.等待(wait)和通知(notify)
首先要知道,这两方法是Object类中的方法,也就是说任何类都继承了这两方法。
在一个线程中,当一个对象调用wait()方法后,当前线程就会等待在这个对象上。直到另外一个线程调用了obj.notify()方法后,才能解除等待。要注意的第一点,这里的对象是同一个!第二点,这个对象必须被用作监视器锁!第三点,等待的线程必须获得了监视器锁后才能执行,并不是说另一个线程执行了notify()方法后就能被唤醒了!
public class WaitNotifyDemo{
final static Object obj = new Object();
static class T1 extends Thread {
@Override
public void run() {
synchronized (obj) {
System.out.println(System.currentTimeMillis()+":T1 start!");
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+":T1 end!");
}
}
}
static class T2 extends Thread {
@Override
public void run() {
synchronized (obj) {
System.out.println(System.currentTimeMillis()+":T2 start!");
obj.notify();
try {
Thread.sleep(2000);//为了看的明显,等待2s
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+":T2 end!");
}
}
}
public static void main(String[] args) {
new T1().start();
new T2().start();
}
}
5.线程的加入(join)和谦让(yield)
线程的加入:在一个线程A中调用线程B的join()方法,那么线程A就必须等线程B的逻辑执行完成后,才能继续往下执行自己A的逻辑。加入实际就是一起走的意思!下面例子,最后i肯定是100000.
public class ThreadJoinDemo{
public volatile static int i = 0;
static class T1 extends Thread {
@Override
public void run() {
for(i=0;i<100000;i++);
}
}
public static void main(String[] args) throws InterruptedException {
T1 t1 = new T1();
t1.start();
t1.join();
System.out.println(i);
}
}
线程资源让出-yield:Thread.yield()是一个静态的本地方法。让出的意思很明确,让出CPU资源。但是,让出了我还要争夺的!
四.线程的分类管理
1.线程的分组-线程组
给线程分个组,起个好听的名字吧,方便管理,默认新建的线程所在的线程组是创建线程的父组。
public class ThreadGroupDemo implements Runnable{
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadGroup tg = new ThreadGroup("zhaodf");
Thread t1 = new Thread(tg, new ThreadGroupDemo(), "T1");
Thread t2 = new Thread(tg, new ThreadGroupDemo(), "T2");
Thread t3 = new Thread(new ThreadGroupDemo());
t1.start();
t2.start();
t3.start();
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getThreadGroup().getName()+"_"+Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2.守护线程:守护线程守护的是谁?守护的是用户线程,用户线程不存在了,它就没有意义了,因此也就停掉了。
public class Daemon {
public static class DaemonT extends Thread{
@Override
public void run() {
while(true){
System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"_i am alive");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Thread t = new DaemonT();
//必须在start方法之前设置守护线程,这样t变为守护线程,而主线程main成为用户线程。当主线程休眠2秒后,守护线程也退出
//如果放在start之后,会抛出Exception in thread "main" java.lang.IllegalThreadStateException异常
t.setDaemon(true);
t.start();
System.out.println(System.currentTimeMillis()+"_"+"主线程名称:"+Thread.currentThread().getName());
Thread.sleep(2000);
}
}
3.线程的优先级:
线程的优先级并不能保证线程优先执行,这点要注意。
public class PriorityDemo{
public static class HightPriority extends Thread{
static int count = 0;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
synchronized (PriorityDemo.class) {
count++;
if(count>10000){
System.out.println("HightPriority is complete");
break;
}
}
}
}
}
public static class LowerPriority extends Thread{
static int count = 0;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
synchronized (PriorityDemo.class) {
count++;
if(count>10000){
System.out.println("LowerPriority is complete");
break;
}
}
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread high = new HightPriority();
Thread low = new LowerPriority();
//设置优先级并不能保证线程一定优先执行
high.setPriority(Thread.MAX_PRIORITY);
low.setPriority(Thread.MIN_PRIORITY);
high.start();
low.start();
}
}

- 大小: 34.8 KB

- 大小: 30.8 KB

- 大小: 33 KB

- 大小: 15.1 KB

- 大小: 3.8 KB

- 大小: 26.7 KB
分享到:
相关推荐
- Java内存管理的核心是对象生命周期的管理,当一个对象不再被引用时,垃圾回收器会将其占用的内存空间回收。 2. **垃圾回收器的工作原理** - **可达性分析**:垃圾回收器通过一系列称为“根”(如局部变量、静态...
本篇讲解主要围绕Android中的多线程应用,基于Java的多线程基础进行展开。 1. **为什么要使用多线程?** a) **提高用户体验/避免ANR**:在Android中,主线程(也称UI线程)负责处理用户界面的更新和事件响应。...
第一篇 基础篇 第1章 Java简介(精彩视频:33分钟) 21 1.1 Java的平台简介 21 1.2 安装工具包 22 1.2.1 下载JDK 22 1.2.2 安装JDK 24 1.2.3 查看与设置环境变量 25 1.2.4 JDK常用命令 27 1.2.5 Java各个目录含义 28...
本题集涵盖了从基础到高级的多个领域,包括技巧篇、智力篇、Java篇、JSP篇、Servlet篇、应用服务器篇、J2EE与MVC篇、设计模式篇以及数据库篇。以下是对这些篇章的详细解读: **第一章 技巧篇** 在面试过程中,自我...
- 全局内存是指在整个程序生命周期中都存在的内存区域,包括`.data`和`.bss`段,用于存放全局变量和静态局部变量。 **1.4 大内高手—内存管理器** - 内存管理器是负责管理和优化程序使用的内存的一种技术或工具。...