黑马程序员09多线程

来源:互联网 发布:高阶矩阵计算 编辑:程序博客网 时间:2024/04/28 14:17

------- android培训、java培训、期待与您交流! ----------

一、基本概念

线程:是依赖于进程的执行绪(执行路径/控制单元),是程序使用CPU的基本单位。

进程:当前正在执行的程序,代表一个应用程序在内存中的执行区域。

 多进程:同一时间段内执行多个任务。同一时刻只能执行一个任务。如Windows为代表的操作系统。

多进程并不提高某个程序的执行速度,仅仅是提高了CPU的使用率。真正的多进程执行是指多核同时计算。

 单线程:一个进程中,只有一个线程执行。

多线程:同一个进程中,多个线程执行。这多个线程共享该进程资源(堆内存与方法区),栈内存独立,即每一个线程占用一个栈。

线程两种调度模型:

分时调度模型   所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片。

抢占式调度模型   优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个。(线程随机性)

Java使用的为抢占调度模型。

线程并行与线程并发

线程并行:正常的多线程执行就是线程并行。即逻辑上同一时间同时运行。

线程并发(异常):由于线程抢占而不应出现的某一时刻的线程及相关数据状态。如并发修改异常的产生。

JVM的启动支持多线程:

JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程”,然后主线程去调用某个类的 main 方法。所以 main方法运行在主线程中。


线程生命周期



二、线程创建方式
线程创建方式一:
继承Thread类.要覆盖其run方法,调用线程的start方法.
作用:1.启动线程
      2.运行run方法。目的是将自定义的代码存储在run方法中,让线程运行
cpu每次只执行一个程序,只是在快速的不同线程间切换,表现了多线程的随机性

class demo extends Thread{  public void run(){  }}


run方法用于存储线程要运行的代码。
demo demo=new demo();创建对象就创建了一个线程。
run方法和 start方法
run方法  仅仅是对象调用方法,并没有运行线程
start方法  是开启线程并且执行线程中的run方法


创建线程的第二种方式:实现Runnable接口。
创建线程 
Thread t=new Thread(new 对象名());
步骤:
1,定义类实现Runnable接口。
2,覆盖接口中的run方法(用于封装线程要运行的代码)。
3,通过Thread类创建线程对象;
4,将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。
      为什么要传递呢?因为要让线程对象明确要运行的run方法所属的对象。
5,调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。


实现方式和继承方式有什么区别?
继承Thread类:线程代码块存放在Thread子类的run方法中
实现Runnable,线程代码存放在接口的子类的run方法中,可以被多实现。

继承方式有局限性。要被实现多线程的一个类 如果继承了父类 就不能再继承Thread类。
实现方式就变面了单继承的局限性。

方式一与方式二的区别

方式一:当类去描述事物,事物中有属性和行为。如果行为中有部分代码需要被多线程所执行,同时还在操作属性。就需要该类继承Thread类,产生该类的对象作为线程对象。可是这样做会导致每一个对象中都存储一份属性数据。无法在多个线程中共享该数据。加上静态,虽然实现了共享但是生命周期过长。

方式一:如果一个类明确了自己的父类,那么它就不可以再继承Thread。因为java不允许类的多继承。

方式二:将线程与运行的业务逻辑分离,可以让多个线程共享业务逻辑中的数据。

方式二:可以让业务类不再继承Thread而专注于业务继承其他类,避免了单继承的局限性。

三、多线程——Lock锁简介

相较于synchronized方式,Lock锁的出现使同步操作更为灵活。无需使用限制性强的代码块。

Lock同样为抽象类,需要使用其子类ReentrantLock的对象完成方法调用。

主要方法:

public void lock()获取锁

public void unlock() 释放锁

在多线程的代码编辑过程中,由于考虑得不够周全,会出现死锁的情况。

线程死锁代码:备注

原因分析:

线程1将锁1锁住,线程2将锁2锁住,而线程1要继续执行锁2中的代码,线程2要继续执行锁1中的代码,但是此时,两个锁均处于锁死状态。最终导致两线程相互等待,进入无限等待状态。

有同步代码块的嵌套动作。

解决方法:

不要写同步代码块嵌套。

示例代码


private Lock lock=new ReentrantLock();private Condition condition =lock.newCondition();public void cet(String name ) throws {   lock.lock();   try   {      while(flag)           contidition.await();       this.name=name+"--"+count++;       sop(Thread.currentThread().getName()+"...生产者..."+this.name)       flag=true;        condition.signalAll();    }    finally    {       lock.unlock();            }}



四、多线程通信

线程间通信:多个线程在操作同一个资源,但是操作的动作不同。

1.是不是两个或两个以上的线程。解决办法 两个线程都要被同步。
2.是不是同一个锁。解决办法 找同一个对象作为锁。

等待唤醒机制。
wait后,线程就会存在线程池中,notify后就会将线程池中的线程唤醒。
notifyAll();唤醒线程池中所有的线程。
实现方法 :
给资源加个标记 flag   
synchronized(r)

{ while(r.flag)//多个生产者和消费者   if(r.flag)//一个生产者和消费者  r.wait();  代码   r.flag=true;  r.notify();  r.notifyAll();}


例子:

package cn.itcast.thread;/* * 多线程的通信 * 输入线程赋值 * 输出线程打印值 *  *///资源对象class Resource{String name;String sex;boolean b = false;//定义,b=true,赋值完成,b = false打印完成}//定义输入线程class Input implements Runnable{Resource r  ;Input(Resource r){this.r = r;}public void run(){int x = 0 ;while(true){synchronized(r){//输入线程,判断b的值,如果是真,等待if(r.b==true)try{r.wait();}catch(Exception e){}if(x%2==0){r.name = "张三";r.sex = "男";}else{r.name = "lisi";r.sex = "nv";}x++;//标记改成truer.b = true;//唤醒输出线程r.notify();}}}}//定义输出线程,打印变量值class Output implements Runnable{Resource r ;Output(Resource r){this.r = r;}public void run(){while(true){synchronized(r){if(r.b==false)try{r.wait();}catch(Exception e){}System.out.println(r.name+"..."+r.sex); r.b = false; r.notify();}}}}public class ThreadDemo6 {public static void main(String[] args) {Resource  r = new Resource();Input in = new Input(r);Output out = new Output(r);Thread tin = new Thread(in);Thread tout = new Thread(out);tin.start();tout.start();}}


0 0
原创粉丝点击