java线程概述

/**
多线程概述:什么是多线程?
首先,什么是进程?
进程是系统分配资源的基本单位,对于windows系统而言。
进程是程序的一次运行。
一个进程中至少有一个线程存在,因为线程才是实际运行单元。
线程:是指程序中的控制单元,一条执行路径。
一个程序可以有多线程并发执行,每个线程是一个控制单元。一个程序可以有多条执行线路,
每个执行线路代表一个线程。
线程的创建是由底层系统完成的,对于Java中的线程是jvm通过调用底层的windows操作系统的功能创建的。

注意一个线程在程序上的体现和内存中体现就是一个对象,一个线程对象。用一个Thread类或者其子类可以创建
很多个不同的线程对象,即很多个不同的线程。

线程的创建:线程的创建方式有两种:
1、通过继承Thread类,覆写其中的run方法。
2、通过实现Runnable接口,覆写其中的run方法。

线程是一类事物,是指程序的一个控制单元。Java中有对于此类的描述,叫做Thread类,该类中的run方法,即
public void run(){};,这个空参数的内部什么操作也没有的方法是供Thread的子类覆写其,并在run中存放
该线程要执行的代码。
Thread类的一些方法:
public void run();
public String getName();//返回该线程的名称。
public String setName(String name);//设置该线程的名称。
public static Thread currentThread();//返回对当前正在执行的线程对象的引用。
public static void sleep(long millis,int nanos);//使得执行该方法的线程进入到阻塞状态,开始休眠。
第一种创建方式:
1、通过继承Thread类。
2、覆写其中的run方法。
3、将该线程需要运行的代码存放到run()方法中
4、创建子类对象
5、调用子类对象的start()方法,开启线程,并调用run方法。

第二种创建方式:
1、通过实现Runnable接口,定义类。
2、覆写其中的run方法。
3、将需要线程运行的代码存放到run()方法中
4、创建自定义类的对象。
5、创建Thread类的对象,并将自定义类的对象作为参数传递给Thread类的带参数的构造函数。创建出一个Thread类的
对象。
6、调用Thread类对象的start()方法,开启线程,并调用自定义类对象的run方法。

两种方式的区别比较:
区别:
第二种方式,实现Runnable接口的类并不是一个线程类,创建该接口的子类对象,并不是创建了线程对象。
第二种方式是通过创建Thread类的对象,并指定所要运行的run方法位于哪个对象中,来创建线程对象的。

优缺点:第一种方式,由于Java的单继承,使得Thread子类不能在继承其他的类,无法成为其他类的一种。有一定的
局限性。而第二种方式,通过实现Runnable接口的方式,避免了继承Thread的,所以是避免了单继承的局限性。
在实际开发中尽可能使用第二种方式,第二种方式是将Runnable接口所定义的功能扩展到了接口子类上。
凡是实现了Runnable接口的类的对象,都可以交给Thread类的对象来运行其中特定的内容。

线程的运行状态:
一个线程的运行状态有5种:是一个类似于生物一样的声明周期。
分别是新建状态、就绪状态、运行状态、阻塞状态、死亡状态。具体如下:

1、新建(new): 用new语句创建完一个线程,该线程处于新建状态,此时它和其他java对象一样,仅仅在Heap中被分配了内存。
当一个线程处于新建状态时,它仅仅是一个空的线程对象,系统不为它分配资源。
例如:Thread t = new Thread(new Runner());
2、就绪(runnable): 程序通过线程对象调用启动方法start()后,系统会为这个线程分配它运行时所需的除处理器cpu之外的
所有系统资源。这时,它处在随时可以运行的状态,在随后的任意时刻,只要它获得处理器即会进入运行状态(running)。
例如:t.start();
3、运行(running): 处于这个状态的线程占用cpu,执行程序代码。在并发环境中,如果计算机只有一个cpu,那么任何时刻
只会有一个线程处于这个状态。如果计算机中有多个cpu(即多核),那么同一时刻可以让几个线程占用不同的cpu,使它们都处
于运行状态,只有处于就绪状态(runnable)的线程才有机会转到运行状态。其他线程状态不可以直接切换到运行状态,
必须先进入就绪状态才可以。
4、阻塞(blocked): 阻塞状态是指线程因为某些原因放弃cpu,暂时停止运行。当线程处于阻塞状态时,java虚拟机不会给
线程分配cpu,直到线程重新进入就绪状态,它才有机会转到运行状态。
阻塞状态可以分为以下3中:
@1,位于对象等待池中的阻塞状态(blocked in object‘s wait pool):当线程处于运行状态时,如果
执行了某个对象的wait()方法,java虚拟机就会把线程放到这个对象的等待池中。
@2,位于对象锁池中的阻塞状态(blocked in object‘s lock pool):当线程处于运行状态,
试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,JVM就会把这个线程放到这个
对象的锁池中。
@3,其他阻塞状态(otherwise blocked):当前线程执行了sleep()方法,或者调用了其他线程的join()方法,
或者发出了I/O请求时,就会进入这个状态。当一个线程执行System.out.println()或者System.in.read()方法时,
就会发出一个I/O请求,该线程放弃cpu,进入阻塞状态,直到I/O处理完毕,该线程才会恢复执行。
5、死亡(dead): 当线程退出run()方法时,就进入死亡状态,该线程结束生命周期。线程有可能是正常执行完run()方法而
退出,也有可能是遇到异常而退出。不管线程是正常结束还是异常结束,都不会对其他线程造成影响。

线程状态之间的切换,新建状态只可以进入就绪,就绪可以到运行,运行也可以到就绪,运行可以到阻塞,阻塞可以到
就绪,新建、就绪、运行、阻塞都可以到死亡。

多线程的安全问题:当多个线程执行同一块代码,操作共享数据的时候,就会出现线程安全问题。

线程安全问题出现的前提:
1、至少有两个或者两个以上的线程存在。
2、至少有两条或者两条以上的代码操作共享资源。

解决方法:让线程同步。
什么事线程同步?什么是线程异步?
线程具有随机性或者说异步性,即每个线程都以各自独立的、不可预知的速度向前推进。即每个线程各自执行各自
的,互不相干。
同步是指:因为需要互斥的使用某一个共享资源,或者需要协同合作而产生了相互制约关系。即线程的推进执行中
需要考虑其他线程的执行情况了。
解决线程安全的问题,是使用同步代码块或者同步函数。关键字为synchronized。

同步代码块:
synchronized(对象)
{
需要同步的代码块
}
同步函数:
synchronized 返回值类型 函数名()
{
//函数体,需要同步的代码。
}
同步的部分一次只能有一个线程进入运行,同步的部分都有一个锁,无论是同步代码还是同步函数,这个锁是一个对象。
对于同步代码块就是指synchronize(对象)中的对象。而对于同步函数,如果是非静态的同步函数,则是调用该
非静态同步函数的对象,即this;如果是静态的同步代码块,则是该静态同步函数所属的类的类对象,即该类的
字节码文件对象,即类名.class,“类名.class”就是这个对象的名称,该对象的类型是Class类型。
同步部分的进入规则是,只有拿到锁的线程才可以进入同步部分执行,执行完同步部分后,再将该锁释放,没有拿到该
锁的线程无法进入同步部分,只能是在外等候,因为缺少资源,放弃CPU,进入阻塞状态。

同步:
好处:解决了线程安全问题
弊端:因为每次进入同步部分,都需要对同步部分进行锁判定,降低了程序的效率。但有时这种牺牲是必要的。

死锁:死锁是指由于多个线程之间占有对方需要的锁,而又请求对方占有的锁,造成的一个无法解开的局面,死锁。
死锁产生的原因:同步中嵌套同步。
例1:
synchronized(lockA)
{
synchronzied(lockB)
}
synchronized(lockB)
{
synchronized(lockA)
}
例2:
sychronized void show()
{
method();
}
sychronized void method()
{
show();
}
单例模式中的懒汉式,即延迟加载的方式,当有多线程访问时,会出现线程安全问题。解决方法是加同步代码块或者同步函数。
但是加入同步后,会降低程序的效率,因为每个线程在进入同步部分时,都要进行同步锁的判断。而优化的方案是,使用
双重判断,来提高程序的效率。
*/

class Demo extends Thread
{
Demo(String name)
{
super(name);
}
public void run()
{
for(int x=0; x<60; x++)
{
System.out.println(Thread.currentThread().getName()+"---run----"+x);
}
}
}

class ThreadDemo
{
public static void main(String[] args)
{
Demo d = new Demo("Demo");
// System.out.println(d.getName());

// d.run();

d.start();
for(int x =0 ;x<60; x++)
{
System.out.println(Thread.currentThread().getName()+"---main---"+x);
}

}
}
/*
主函数也是一个线程,它的名称叫做main,一般称为主线程。
而其他线程的名称可以在创建时就赋值,如果使用默认名称,则为Thread-编号。
run()和start()的区别:
run方法只是用来存储线程需要运行的代码。
start()方法是用来开启线程的,只有开启线程,系统才会给该线程分配除cpu以外的资源。然后会调用run方法。
*/

时间: 2024-07-30 06:55:59

java线程概述的相关文章

java线程基础梳理

java线程 概述 进程:运行时概念,运行的应用程序,进程间不能共享内存 线程:应用程序内并发执行的代码段,可以共享堆内存和方法区内存,而栈内存是独立的. 并发理解:在单核机器上,从微观角度来看,一段时间内cup只能执行一个任务,但是因为cup在只执行一段代码段的时候大部分的时间是处于等待程序的,所以可以再开几条程序,然后通过轮询机制,让cpu执行多个进程,从宏观角度来看就是所谓的并发.如果机器是多核,那么就是真正的并发. 线程调度模型 线程的调度模型分为: 分时调度模型和抢占式调度模型,Jav

Java线程池 Executor框架概述

线程池的意义 循环利用线程资源,避免重复创建和销毁线程 线程池的任务是异步执行的,只要提交完成就能快速返回,可以提高应用响应性 Java线程池还有一个很重要的意义:Java线程池就是JDK 5 推出的Executor框架,在此之前Java线程既是工作任务又是执行机制,而Executor框架把工作任务与执行机制分离开来:工作任务包括Runnable接口和Callable接口,而执行机制由Executor接口提供. Executor 类继承体系 Executor框架由三个部分组成 工作任务:Runn

java线程详细介绍

目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1

Java IO 概述

原文链接作者: Jakob Jenkov   译者: 李璟([email protected])  校对:方腾飞 在这一小节,我会试着给出Java IO(java.io)包下所有类的概述.更具体地说,我会根据类的用途对类进行分组.这个分组将会使你在未来的工作中,进行类的用途判定时,或者是为某个特定用途选择类时变得更加容易. 输入和输出 – 数据源和目标媒介 术语“输入”和“输出”有时候会有一点让人疑惑.一个应用程序的输入往往是另外一个应用程序的输出.那么OutputStream流到底是一个输出到

Java 线程第三版 第八章 Thread与Collection Class 读书笔记

JDK1.2引入最有争议性的改变是将集合类默认为不是Thread安全性的. 一.Collection Class的概述 1. 具有Threadsafe 的Collection Class: java.util.Vector(List) 列表集合,通过索引操作. java.util.Stack(List) 继承自Vector,提供LIFO的顺序操作push进入,pop出元素. java.util.Hashtable(Map) 一个简单.无序的key与value的映射. java.util.conc

Java 线程第三版 第五章 极简同步技巧 读书笔记

一.能避免同步吗? 取得锁会因为以下原因导致成本很高: 取得由竞争的锁需要在虚拟机的层面上运行更多的程序代码. 要取得有竞争锁的线程总是必须等到锁被释放后. 1. 寄存器的效应 计算机有一定数量的主寄存器用来存储与程序有关的数据. 从逻辑上的观点来看,每个Thread都有自己的一组寄存器.当操作系统将某个Thread分配给CPU时,它会把该Thread特有的信息加载到CPU的寄存器中.在分配不同的Thread给CPU之前,它会将寄存器的信息存下来.所以Thread间绝不会共享保存在寄存器的数据.

Java线程浅学习

 线程概述 线程是程序运行的基本执行单位,当操作系统执行一个程序时,会创建一个进程,而这个进程至少创建一个线程(主线程)作为这个程序的入口点.所以,在操作系统中运行的程序都至少有一个主线程. 进程和线程是现代操作系统必不可少的运行模型,在操作系统中可以有多个进程,这些进程包括系统进程(系统内部创建的进程)和用户进程(用户程序创建的进程),一个进程可以有多个线程.进程之间不存在内存共享,就是说,系统中的进程都是在各自的内存空间中运行的.但是一个进程中的线程可以共享系统分配给这个进程的内存空间.

Java 线程第三版 第九章 Thread调度 读书笔记

一.Thread调度的概述 import java.util.*; import java.text.*; public class Task implements Runnable { long n; String id; private long fib(long n) { if (n == 0) return 0L; if (n == 1) return 1L; return fib(n - 1) + fib(n - 2); } public Task(long n, String id)

JAVA线程池的使用

概述 new Thread的弊端如下: a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom. c. 缺乏更多功能,如定时执行.定期执行.线程中断. 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间.那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?在Java中可