1. 线程的概念

     1.1多进程与多线程

进程:一个正在执行的程序.每个进程执行都有一个执行顺序,该顺序是一个执行路径,或叫一个控制单元. 一个进程至少有一个线程.

    线程:就是进程中的一个独立的控制单元. 线程控制这进程的执行.

多进程的缺点:进程切换开销大;进程间的通信很不方便。

多线程: 指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务,线程切换的开销小 。

     1.2线程的状态

Java语言使用Thread类及其子类的对象来表示线程,新建的线程在它的一个完整的生命周期通常要经历5种状态.

  

冻结状态:在sleep和wait时, 既没有运行资格,有没有执行权

阻塞状态: 具备运行资格, 没有执行权

1.3线程调度与优先级(多线程的特性:随机性)

Java采用抢占式调度策略,下面几种情况下,当前线程会放弃CPU: 
          (1)当前时间片用完; 
          (2)线程在执行时调用了yield() 或sleep() 方法主动放弃;  
          (3)进行I/O 访问,等待用户输入,导致线程阻塞;或者为等候一个条件变量,线程调用wait()方法;    
          (4)有高优先级的线程参与调度。 
     线程的优先级用数字来表示,范围从1~10。主线程的默认优先级为5
          Thread.MIN_PRIORITY=1
          Thread.NORM_PRIORITY=5

    Thread.MAX_PRIORITY=10


2. 多线程编程方法

     2.1 Thread类简介

Thread类综合了Java程序中一个线程需要拥有的属性和方法,其构造方法如下:

public Thread (ThreadGroup group,Runnable target,String name);

public Thread();

public Thread(Runnable target);

public Thread(Runnable target,String name);

public Thread(String name);

public Thread(ThreadGroup group,Runnable target);

public Thread(ThreadGroup group,String name);

Thread类的主要方法以及功能如表

2.2 继承Thread类实现多线程

    需要重写run方法实现线程的任务.需要注意的是,程序中不要直接调用此方法,而是调用线程对象的start()方法启动线程,让其进入可调度状态,线程获得调度自动执行run()方法.

2.3 实现Runnable接口编写多线程

    通过 Thread 类的构造函数public Thread(Runnable target)可以将一个Runnable 接口对象传递给线程,线程在调度时将自动调用Runnable 接口对象的run方法。

  实现方式和继承方法的区别:

    实现方式的好处:避免了单继承的局限性.在定义线程时,建议使用实现方式.


3. 线程资源的同步处理

3.1 临界资源问题

Java对于多线程的安全问题提供了专业的解决方式:  就是同步代码块

  synchronized(对象) {

    需要被同步的代码

  }

对象如同锁,持有锁的线程可以在同步中执行.

没有持有锁的线程及时获取cpu的执行权,也进不去,因为没有获取锁.

同步的前提:

1.必须要有两个或者以上的线程

2.必须要多个线程使用同一个锁

好处:解决了多线程的安全问题

弊端:多个线程需要判断锁,较为消耗资源.

同步函数使用的是哪个锁:

函数需要被对象调用,那么函数都有一个所属对象的引用.就是this.

所以同步函数使用的锁是this锁.静态函数使用的是该方法所在类的字节码文件对象.

   懒汉式增强  

 class Single{
     private Single(){}
     private static Single s = null;
     public static Single getInstance(){
         if(s == null){
             synchronized(Single.class){
                 if(s == null)
                     s = new Single();
             }
         }
         return s;
     }
 }

3.2 wait()和notify()

3.3 避免死锁

多个线程相互等待对方释放持有的锁,并且在得到对方锁之前不释放自己的锁.(自己能写一个死锁代码)

 /*
  * 死锁: 同步中嵌套同步容易发生
  */

 public class LockDemo {

     public static void main(String[] args) {
         Test t = new Test(false);
         Test t2 = new Test(true);
         new Thread(t).start();
         new Thread(t2).start();

     }

 }

 class Test implements Runnable{
     private boolean flag;
     Test(boolean flag){
         this.flag = flag;
     }
     public void run(){
         if(flag){
             try{Thread.sleep(30);}catch(Exception e){}
             synchronized(KK.oa){
                 System.out.println("if a");
                 synchronized(KK.ob){
                     System.out.println("if b");
                 }
             }
         }
         else{
             synchronized(KK.ob){
                 System.out.println("else b");
                 synchronized(KK.oa){
                     System.out.println("else a");
                 }
             }
         }
     }
 }

 //自定义两个锁
 class KK{
     static Object oa = new Object();
     static Object ob = new Object();
 }

4. 线程间通信

思考1: wait(),notify(),nofifyAll()用来操作线程为什么定义在Object类中?

1.这些方法存在同步中,用来操作同步中的线程,必须要标志它们所操作线程的只有锁.

2.使用这些方法必须标识出所属同步的锁,只有同一个锁上被等待线程,可以被同一个锁上notify唤醒.不可以对不同锁中的线程进行唤醒.

3.锁可以是任意对象,所以任意对象调用的方法一定定义Object类中.

思考2:wait(),sleep()有什么区别?

wait():释放资源,释放锁

sleep():释放资源,不释放锁

 //线程通信: 取mike, 取丽丽
 public class Demo2 {

     public static void main(String[] args) {
         Person p = new Person();
         new Thread(new Input(p)).start();
         new Thread(new Output(p)).start();
     }

 }

 class Person{
     private String name ;
     private String sex ;
     private boolean flag = false;

     public synchronized void set(String name, String sex){
         //flag为true,表示已存在
         if(flag){
             try {wait();}catch (InterruptedException e) {e.printStackTrace();}
         }
         //flag为false,表示没人可加
         this.name = name;
         this.sex = sex;
         flag = true;
         this.notify();
     }

     public synchronized void out(){
         //flag为false,表示无人没法取
         if(!flag){
             try {wait();}catch (InterruptedException e) {e.printStackTrace();}
         }
         //flag为true,表示有人可以取出
         System.out.println(toString());
         flag = false;
         this.notify();
     }

     public String toString(){
         return "姓名:"+name+"性别:"+sex;
     }
 }

 class Input implements Runnable{
     private Person p;

     Input(Person p){
         this.p = p;
     }

     public void run(){
         boolean flag = false;
         while(true){
                 if(flag){
                     p.set("likai","男");
                     flag = false;
                 }
                 else{
                     p.set("tangll","女");
                     flag = true;
                 }
         }
     }
 }

 class Output implements Runnable{
     private Person p;

     Output(Person p){
         this.p = p;
     }

     public void run(){
         while(true){
             p.out();
         }
     }
 }

线程通信Demo1

 public class Demo3 {

     public static void main(String[] args) {
         Bridge b = new Bridge();
         for(int i=1;i<6;i++){
             new Thread(new Person(b,"由北向南第"+i+"人")).start();
         }

         for(int i=1;i<7;i++){
             new Thread(new Person(b,"由南向北第"+i+"人")).start();
         }
     }
 }

 class Bridge{
     private String name;
     private boolean flag;
     public synchronized void UpBridge(){
         if(flag){
             try {
                 wait();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
         flag = true;

     }
     public synchronized void DownBridge(){
         flag = false;
         notifyAll();
     }
 }

 class Person implements Runnable{
     private Bridge bridge;
     private String pName;

     Person(Bridge bridge, String pName){
         this.bridge = bridge;
         this.pName = pName;
     }

     public void run() {
         bridge.UpBridge();
         try{
             Thread.sleep(80);
         }catch(InterruptedException e){}
         bridge.DownBridge();
         System.out.println(pName);
     }

 }

过桥问题

生产消费者问题

生产消费者问题--JDK1.5提供的多线程升级解决方法

将同步synchronized替换成Lock操作.

将Object中的wait,notify,notifyAll方法替换成Condition对象.

该对象可以Lock锁进行获取.

    该实例中,实现了本方只唤醒对方的操作.

停止线程

1.定义循环结束标记

因为线程运行代码一般都是循环,只是控制了循环即可.

2.使用interrupt(中断)方法: 该方法是强制结束线程的冻结状态,使线程回到运行状态中来.这样就可以操作标记结束.

(注)stop方法和suspend方法已过时不在再使用.

setDeamon()方法

标记为后台线程, 当所有前台前程结束后会Java虚拟机退出. 该方法必须在启动线程前调用.

join()方法

等待该线程终止, 其实是抢夺CPU执行权.

当A线程执行到B线程的.join()方法, A就会等待. 等B线程都执行完, A才会执行. join可以用来临时加入线程执行.

toString()

返回该线程的字符串表示形式,包括线程名称,优先级和线程组

yield()

暂停当前执行的线程对象,并执行其他线程

06_Java多线程、线程间通信的更多相关文章

  1. 【原】iOS多线程之线程间通信和线程互斥

    线程间通信 1> 线程间通信分为两种 主线程进入子线程(前面的方法都可以) 子线程回到主线程 2> 返回主线程 3> 代码 这个案例的思路是:当我触摸屏幕时,会在子线程加载图片,然后 ...

  2. C++多线程编程(三)线程间通信

    多线程编程之三——线程间通讯 作者:韩耀旭 原文地址:http://www.vckbase.com/document/viewdoc/?id=1707 七.线程间通讯 一般而言,应用程序中的一个次要线 ...

  3. Java多线程基础——线程间通信

    在使用多线程的时候,经常需要多个线程进行协作来完成一件事情.在前面两章分析了Java多线程的基本使用以及利用synchronized来实现多个线程同步调用方法或者执行代码块.但上面两章的内容涉及到的例 ...

  4. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

  5. Java多线程编程核心技术---线程间通信(二)

    通过管道进行线程间通信:字节流 Java提供了各种各样的输入/输出流Stream可以很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程间直接传送数据,一个线程发送 ...

  6. Java多线程编程核心技术---线程间通信(一)

    线程是操作系统中独立的个体,但这些个体如果不经过特殊处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一.线程间通信可以使系统之间的交互性更强大,在大大提高CPU利用率的同时还会使程序员对各 ...

  7. java多线程系列5-死锁与线程间通信

    这篇文章介绍java死锁机制和线程间通信 死锁 死锁:两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象. 同步代码块的嵌套案例 public class MyLock { // 创建两 ...

  8. volatile关键字与线程间通信

    >>Java内存模型 现在计算机普遍使用多处理器进行运算,并且为了解决计算机存储设备和处理器的运算速度之间巨大的差距,引入了高速缓存作为缓冲,缓存虽然能极大的提高性能,但是随之带来的缓存一 ...

  9. Java笔记(二十)&hellip;&hellip;线程间通信

    概述 当需要多线程配合完成一项任务时,往往需要用到线程间通信,以确保任务的稳步快速运行 相关语句 wait():挂起线程,释放锁,相当于自动放弃了执行权限 notify():唤醒wait等待队列里的第 ...

随机推荐

  1. 在SQL中 给字符串补0方法

    --第一种方法SELECT RIGHT('00000'+CAST(ID AS nvarchar(50)),5) FROM dbo.TableName --左边补0,如 00001,00039 SELE ...

  2. mpi4py实践

    版权声明:本文为博主原创文章,未经博主允许不得转载. 1.概述 MPI(Message Passing Interface),消息传递接口,是一个标准化和轻便的能够运行在各种各样并行计算机上的消息传递 ...

  3. web安全攻防----环境搭建篇

    1.安装虚拟机vMware. 2.在虚拟机上安装kali系统. *Kali为linux操作系统的一个发行版. 3.安装Xshell *Xshell是一个强大的安全终端模拟软件,它支持SSH1, SSH ...

  4. Linux 信号(三)—— sigaction 函数

    ilocker:关注 Android 安全(新入行,0基础) QQ: 2597294287 #include <signal.h> int sigaction(int signo, con ...

  5. 利用Mongoose来结构化模式与验证

    Mongoose是一个文档对象模型(ODM)库,为MongoDB Node.js原生驱动程序提供更多的功能. 把结构化的模式应用到一个MongoDB集合,提供了验证和类型转换的好处 Mongoose通 ...

  6. Form表单(回车)提交问题

    我们有时候希望回车键敲在文本框(input element)里来提交表单(form),但有时候又不希望如此.比如搜索行为,希望输入完关键词之后直接按回车键立即提交表单,而有些复杂表单,可能要避免回车键 ...

  7. CCNA网络工程师学习进程(3)常规网络设计模型与基本的网络协议

        本节介绍分层的网络设计模型与基本的网络协议,包括ARP协议,ICMP协议和IP协议.     (1)三层网络架构: 一个好的园区网设计应该是一个分层的设计.一般分为接入层.汇聚层(分布层).核 ...

  8. 各种隐藏 WebShell、创建、删除畸形目录、特殊文件名、黑帽SEO作弊(转自核大大)

    其实这个问题,经常有朋友问我,我也都帮大家解决了…… 但是现在这些现象越来越严重,而且手法毒辣.隐蔽.变态,清除了又来了,删掉了又恢复了,最后直接找不到文件了,但是访问网站还在,急的各大管理员.站长抓 ...

  9. Java程序设计的DOS命令基础

    Java程序设计的DOS命令基础 用户使用操作系统和软件有两种方式:命令行界面(Command Line Interface,CLI)和图形界面(Graphical User Interface,GU ...

  10. lecture13-BP算法的讨论和置信网

    这是HInton课程第13课,这一课有两篇论文可以作为课外读物<Connectionist learning of belief networks>和<The wake-sleep ...