Java 线程综述

时间:2022-04-11 20:58:24

线程重在 线程同步线程通信的编程

1.线程与进程? 

线程是指程序在执行过程中,能够执行程序代码的一个执行单元。线程的状态:运行、就绪、挂起(suspend)、结束;

进程是指一段正在执行的程序。

关系:一个进程可以有多个线程。多个线程共享程序的内存空间(包括代码段、数据段和堆空间)及一些进程级的资源(例如打开的文件),但各线程拥有自己的栈空间

多线程的优势:(1)减少程序的响应时间;

(2)与进程相比,线程的创建和切换开销更小;

(3)多CPU或多核计算机本身就具有执行多线程的能力;

(4)使用多线程能够简化程序的结构,是程序便于理解和维护。

2.怎么创建一个线程?//如何实现多线程?

方法1.继承Thread类,重写run()方法

step1.创建一个继承Thread的类(假定类名为A),并重写run()方法

step2.构造一个A类对象,假定对象名为aa

step3.调用aa对象的start()方法

//创建一个线程的方法1
class A extends Thread{//1.创建一个继承Thread的类,并重写run()方法
public void run(){
while(true){
System.out.printf("AAAA\n");
}
}
}
public class ThreadTest {
public static void main(String[] args){
A aa=new A();//2.创建一个A对象
//aa.run();//顺序进行
aa.start();//两个线程同时进行。//3.调用aa对象的start的方法
while(true){
System.out.printf("BBBB\n");
System.out.printf("%s正在执行\n",Thread.currentThread().getName());
}
}
}

方法2.实现Runnable类,并实现该接口的run()方法

step1.创建一个实现Runnable接口的类,假定为A 代码: class A implements Runnable;

step2.创建A类对象aa 代码: A aa=new A();

step3.利用aa构造一个Thread对象tt   Thread tt=new Thread(aa);

step4.调用tt中的start方法  tt.start();

//创建一个线程的方法2
package ThreadTest2;
class A implements Runnable{//用一个类去实现Runnable接口
public void run(){
while(true){
System.out.printf("AAAA\n");
}
}
}
public class ThreadTest2 {
public static void main(String[] args){
A aa=new A();//定义一个A类对象
Thread bb=new Thread(aa);//用aa去实现一个Thread类
bb.start();//调用start方法,实现多线程
while(true){
System.out.printf("BBBB\n");
}
}
}

方法3.实现Callable接口,重写call()方法

import java.util.concurrent.*;

public class CallableTest {
//创建线程
public static class CallableThread implements Callable{
public String call() throws Exception{
return "Hello world";
}
}
public static void main(String[] args){
ExecutorService threadPool=Executors.newSingleThreadExecutor();
//启动线程
Future future=threadPool.submit(new CallableThread());
try{
System.out.println("waiting thread to finish");
System.out.println(future.get());//等待线程结束,并获得返回结果
}catch(Exception e){
e.printStackTrace();
}
}
}

输出结果:

waiting thread to finish
Hello world

比较:前两种方法没有返回值,但最后一种方法有返回值。

当需要实现多线城时,一般推荐使用Runnable接口的方式,其原因是:首先,Thread类定义了多种方法可以被派生类使用或重写,但只有run()是必须被重写的。

其次,许多java程序员认为,一个类仅在他们需要加强或修改时才会被继承,因此没必要继承Thread类。

Callable接口实际是属于Executor框架的功能类Callable接口与Runnable接口的功能是类似的,但提供了比Runnable更强大的功能,表现为:

1)Callable可以在任务结束后返回一个值

2)Callable中的call()方法可以抛出异常

3)Future对象表示异步计算的接否,它能提供检查计算是否完成的方法。

一个类是否可以既继承Thread类又实现Runnable接口?

可以,但是要注意顺序!

public class A extends Thread implements Runnable{
public static void main(String[] args){
Thread t =new Thread(new A);
t.start();
}
}

3.start()和run()的区别?

系统通过start()来启动一个线程,此时线程处于就绪状态而非运行状态,也就意味着这个线程可以被JVM来调度执行;

在调度过程中,JVM通过调用线程类的run()方法来完成实际的操作,当run()结束后,线程就会终止;

调用start()能够异步地调用run()方法,但是直接调用run()方法却是同步的,因此无法达到多线程的目的。

4.同步和异步?

在多线程的环境中,经常会碰到数据的共享问题,即当多个线程需要同时访问一个资源时,他们需要以某种顺序来确保资源在某一时刻只能被一个线程使用,

否则,程序的运行结果将会是不可预测的,在这种情况下,就必须对数据进行同步。同步机制能够保证资源的安全。

要想实现同步,必须要获得每一个线程对象的锁。获得它可以保证在同一个时刻只有一个线程能够进入临界区(访问互斥资源的代码区),并且在这个锁释放之前,

其他线程就不能再进入这个临界区。如果其他线程想要获得该对象的锁,只能进入等待队列等待。

异步与非阻塞类似,由于每个线程都包含了运行时自身需要的数据或方法,因此,在进行输入输出处理时,不必关心其他线程的状态或行为,也不必等到输入输

出处理完毕才返回。

5.多线程同步的实现方法有哪些?

方法1.使用synchronized关键字

(1)用synchronized来修饰一些方法

(2)用synchronized来修饰代码块或对象

方法2.使用wait()方法与notify()或notifyAll()方法:

调用wait()方法,释放对象锁,进入等待状态;通过notify()或notifyAll()方法唤醒的正在等待的其他线程

方法3.Lock

(1)lock()

(2)trylock()

(3)trylock(long timeout,TimeUnit unit)

(1)lockInterruptibly()

 比较:synchronized也lock的区别?

实现线程同步的两种锁机制,其中synchrinized使用Obkect对象本身的notify、wait、notifyAll调度机制;Lock使用Condition进行线程之间的的调度。

  • 用法不同:synchronized既可以加在方法上,也可以加在特定的代码快中,括号表示需要锁的对象;而lock需要显示地指定起始位置和终止位置。另外,synchronized是委托给JVM执行,而Lock是通过代码实现,他有比synchronized更为精确的线程语义。
  • 性能不一样:在资源竞争不是很激烈的情况下,synchronized的性能优于lock,而竞争激烈的情况下,lock的性能优于synchronized。
  • 锁机制不一样:synchronized获得和释放锁的方式是都在块结构中,必须以相反的顺序释放,并自动解锁,不会因为出现异常而导致死锁。而Lock需要开发人员手工去释放,而且必须在finally块中释放,否则会导致死锁。

6.线程的状态及几个概念比较

(1)线程的状态:运行、就绪、阻塞、结束

(2)一些方法及其概念

1)线程的休眠sleep()

暂停执行当前运行中的线程,使之进入阻塞状态,待经过指定的“延迟时间”后再醒来经进入到就绪状态

2)线程的让步yield()

让运行中的线程主动放弃当前获得的的CPU机会,但不是使该线程进入阻塞状态,而是进入就绪状态的

3)线程的串行化joint()

在多线程中,如果在一个线程运行的过程中要用到另一个线程的运行结果,则可以进行线程的串行化处理,即joint()

joint()的作用?

线程的串行化。

4)线程的挂起和恢复

线程的挂起suspend——暂时停止当前运行中的线程,使之转入阻塞状态,并且不会自动恢复

线程的恢复resume——使得一个已经挂起的线程恢复运行

(3)概念比较

1)sleep()和wait()方法

sleep()是使线程暂停执行一段时间的方法;wait()是一种使线程暂停执行的方法。

  • 原理不同:sleep()方法是Thread的静态方法,是线程用来控制自身流程的,它会使得线程暂停执行一段时间,而把机会让给其他线程,等待计时时间一到,此线程会自动苏醒;wait()方法是Object类的方法,用于线程间的通信,这个方法会使当前拥有该对象锁的进程等待,直到其他县城调用notify()方法。
  • 对锁的机制不同:调用sleep()并不会释放锁;调用wait(),线程会释放它所占有的锁。
  • 使用区域不同:wait()只能在同步块或者同步控制的方法中使用;而sleep()可以在任何地方使用。

由于sleep不会释放锁机制,容易造成死锁,因此,一般情况下不建议使用sleep(),而推荐使用wait()方法。

2)sleep()和yeid()方法

  • sleep给其他线程机会时不考虑线程的优先级,而yeild只给相同优先级或者更高优先级的线程以有限运行的机会;
  • sleep方法会使线程转入阻塞状态,而yeild方法只是使当前线程重新回到可执行状态,所以执行yeild()方法的线程有可能进入到可执行状态又马上被执行了。
  • sleep()方法声明了异常,而yeild没有声明异常。
  • sleep()比yield()具有更好的可移植性。 

7.终止线程的方法?

public class endThread {
public class TESTthread implements Runnable{
public void run(){
System.out.println("sleeping");
try{
//用线程的休眠来模拟线程的阻塞
Thread.sleep(5000);
System.out.println("finish");
}catch(Exception e){
System.out.println("interrupted");
}
} }
public static void main(String[] args){
TESTthread bb=new TESTthread();
Thread aa=new Thread(bb);
aa.start();
aa.interrupt(); //打破阻塞
}
}

如果使用在run()中设置flag来达到结束线程的效果时,当线程是非运行状态,比如说,调用sleep()或wait()或I/O阻塞时,这种方法就不能用了。

本节目列出的方法,可以有效地避免这个问题,此时是通过使用interrupt()方法来打破阻塞的情况,当interrupt() 方法被调用时,会抛出异常,可以通过在run()方法中捕获这个异常来让线程安全退出。 

8.守护线程

区别用户线程,当程序中没有用户线程而只有守护线程的时候,JVM终止。

可以通过setDeamon(true)来显式地声明守护线程,并注意,此声明必须在start()方法调用之前。

9.线程通信——生产消费

10.线程同步——卖票

Java 线程综述的更多相关文章

  1. Java String 综述(上篇)

    摘要: Java 中的 String类 是我们日常开发中使用最为频繁的一个类,但要想真正掌握的这个类却不是一件容易的事情.笔者为了还原String类的真实全貌,先分为上.下两篇博文来综述Java中的S ...

  2. java线程day-01

    综述:下面写的是我学习java线程时做的一些笔记和查阅的一些资料总结而成.大多以问答的形式出现. 一.什么是线程? 答:线程是一个轻量级的进程,现在操作系统中一个基本的调度单位,而且线程是彼此独立执行 ...

  3. Java线程并发:知识点

    Java线程并发:知识点   发布:一个对象是使它能够被当前范围之外的代码所引用: 常见形式:将对象的的引用存储到公共静态域:非私有方法中返回引用:发布内部类实例,包含引用.   逃逸:在对象尚未准备 ...

  4. Java线程的概念

    1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...

  5. Java 线程池框架核心代码分析--转

    原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...

  6. 细说进程五种状态的生老病死——双胞胎兄弟Java线程

    java线程的五种状态其实要真正高清,只需要明白计算机操作系统中进程的知识,原理都是相同的. 系统根据PCB结构中的状态值控制进程. 单CPU系统中,任一时刻处于执行状态的进程只有一个. 进程的五种状 ...

  7. 【转载】 Java线程面试题 Top 50

    Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...

  8. 第24章 java线程(3)-线程的生命周期

    java线程(3)-线程的生命周期 1.两种生命周期流转图 ** 生命周期:**一个事物冲从出生的那一刻开始到最终死亡中间的过程 在事物的漫长的生命周期过程中,总会经历不同的状态(婴儿状态/青少年状态 ...

  9. 第23章 java线程通信——生产者/消费者模型案例

    第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...

随机推荐

  1. Struts2入门3 深入学习

    Struts2入门3 深入学习 处理结果和异常 前言: Struts学习的差不多了,还有最后的一点就收官了就是结果处理和异常处理.前面学习Struts主要围绕就是Action以及struts.xml配 ...

  2. Grand Theft Auto V (侠盗列车手5)图形研究

    原文地址:http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/   原文的简介: GTA(侠盗猎车)系列自从1997 ...

  3. Linux06--Shell程序设计02 数据流重定向与管道

    包含3种数据流: •标准输入(stdin):代码为0,符号为<或<<; •标准输出(stdout):代码为1,符号为>或>>; •标准错误输出(stderr):代码 ...

  4. 2016 ASC 移动物联网安全高峰论坛 万物互联时代的安全与隐私

    互联网的发展已经迈入了"万物互联"时代.移动设备作为人.物连接的主要入口,让人们享受高效.便利的"互联生活"的同时,也给用户的安全和隐私带来了前所未有的挑战.正 ...

  5. 《CSS设计指南》阅读笔记

    一.HTML实体 HTML实体常用于生成那些键盘上没有的印刷字符.以一个和号(&)开头,一个分号(:)结尾,二者之间是表示实体的字符串. 如:“左引号(")     ”右引号(&qu ...

  6. 基于pytorch实现HighWay Networks之Highway Networks详解

    (一)简述---承接上文---基于pytorch实现HighWay Networks之Train Deep Networks 上文已经介绍过Highway Netwotrks提出的目的就是解决深层神经 ...

  7. Vim中设置括号自动补全

    1.打开用户Vim配置文件:~/.vimrc vim ~/.vimrc 2.输入以下配置: set tabstop=4 inoremap " ""<ESC>i ...

  8. Redis~Linux环境下的部署

    回到目录 Redis的生产环境建议部署到linux上,而在开发时可以连接windows版本,下面介绍如何在linux上部署redis. $ wget http://download.redis.io/ ...

  9. HTML5 关于本地操作文件的方法

    由于传统 b/s 开发出于安全性的考虑,浏览器对于本地文件的操作权限几乎没有,用户想要操作一个文件基本都是采用先上传到服务器, 再回显给浏览器供用户编辑,裁剪等的方法,这种方式虽然可行,但其对于服务器 ...

  10. Promise及Async&sol;Await

      一.为什么有Async/Await? 我们都知道已经有了Promise的解决方案了,为什么还要ES7提出新的Async/Await标准呢? 答案其实也显而易见:Promise虽然跳出了异步嵌套的怪 ...