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

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. [转]or cad drc 错误

    本文转自 恋上姐的博客 http://blog.sina.com.cn/u/1750715103 用“取缔”一词,是源自<嘻哈四重奏>里面卢导的口头禅,哈哈借用一下!大多数DRC warn ...

  2. Linux基础※※※※如何使用Git in Linux(一)

    参考资料: 1. https://www.linux.com/learn/tutorials/796387-beginning-git-and-github-for-linux-users/ 2. h ...

  3. Protractor AngularJS测试框架教程

    Protractor是一个建立在WebDriverJS基础上的端到端(E2E)的AngularJS JavaScript Web应用程序测试框架.Protractor全自动化真实的模拟用户在真正的浏览 ...

  4. ackerman递归

    定义: n+1        n=0 A(m,n)={A(m-1,1) m=0 A(m-1,A(m,n-1)) n>0,m>0 #include <iostream> #inc ...

  5. hibernate对象关系实现(四)继承实现

    继承实现方式分为三种:subclass; joined-subclass;union-subclass a.类中体现   b.库中体现分为三种: b.1:一种方式:人和学生公用一张表,添加一个辨别字段 ...

  6. html textarea 获取换行

    1.需求: 获取textarea中的换行符,存到数据库中,并在取出时显示出换行操作 2.实践 2.1 发现可以取到换行符 "/n" ,并且可以存储到MySQL数据库中,并不需要特殊 ...

  7. [转载] goroutine背后的系统知识

    原文: http://www.sizeofvoid.net/goroutine-under-the-hood/ 文章写的非常好, 对内部原理解释的非常清楚, 是我喜欢的风格, 感谢作者的精彩文章. = ...

  8. Android SQLite数据库

    SQLite数据库 SQLiteDatabase //管理操作数据库    管理    openDatabase //打开    openOrCreateDatabase //打开或创建    操作 ...

  9. you don't have permission to view it 解决

    the file couldn't be opened because you don't have permission to view it   简单设置下面的选项即可,不要谢我啊! change ...

  10. MapReduce中作业调度机制

    MapReduce中作业调度机制主要有3种: 1.先入先出FIFO      Hadoop 中默认的调度器,它先按照作业的优先级高低,再按照到达时间的先后选择被执行的作业. 2.公平调度器(相当于时间 ...