多线程

来源:互联网 发布:引力波爱因斯坦知乎 编辑:程序博客网 时间:2024/06/05 06:54

一:线程的引入

Ⅰ .进程
1.系统跟配资源调用的独立单位,
2.现在的计算机操作系统基本都是多进程的
3.多进程的意义:提高CPU的使用率
Ⅱ.线程
1.线程介绍
(1)线程依赖于进程存在,一个进程中可能有多个线程
(2)一个进程开启多个线程,他们互相抢占CPU的执行权
特点:随机性
2.单线程
程序的执行路径只有一条
3.多线程
程序的执行路径有多条
Jvm就是一个多线程的程序

  1. 线程介绍
    (1)线程依赖于进程存在,一个进程中可能有多个线程
    (2)一个进程开启多个线程,他们互相抢占CPU的执行权
    特点:随机性
  2. 单线程
    程序的执行路径只有一条
  3. .多线程
    程序的执行路径有多条
    Jvm就是一个多线程的程序
解释:Jvm至少开启了两个进程(1)main主进程(2)垃圾回收器

二:线程的创建

  1. 概况
    Java无法直接调用系统资源,但是c/c++可以,所以Java底层用c/c++封装好了一个类Thread,调用该类可以创建系统的进程

  2. 创建方式1(继承)

开发步骤:

(1)新建一个自定义类继承自Thread(2)重写run()方法:run()方法执行的耗时操作(3)主线程中创建自定义类的对象,启动进程

常用方法

下文默认线程对象为 mt(myThread)public  void start()  //线程启动 mt.start();public final String getName()//返回该线程的名称。mt.getName();public final void setName(String name)//改变线程名称,使之与参数 name 相同。mt.setName();public final void join()throws InterruptedException//等待该线程终止。mt.join();public final int getPriority()//返回线程的优先级。最大:10 最小:1 默认:5mt.getPriority();public static void yield()//暂停当前正在执行的线程对象,并执行其他线程。并不能保证其他线程能够抢到CPU的执行权mt.yield();public final void setDaemon(boolean on)  on指定true,就是设置守护线程...  当子线程全为守护线程时,进程慢慢死亡mt.setDaemon(true);public static void sleep(long millis)throws InterruptedException//在指定的毫秒数内让当前正在执行的线程休眠(暂停执行 mt.sleep;public final void stop()://强迫线程停止执行mt.stop();public void interrupt()//中断线程。 表示中断线程一种状态mt.interrupt();

创建方式2(接口实现)

开发步骤:

(1)自定义一个类实现Runnable接口(2)实现run()方法(3)创建该类对象(4)创建Thread对象,讲(3)中的对象作为参数传递(5)启动进程

常用方法

public static Thread currentThread()           返回对当前正在执行的线程对象的引用。 

创建方式3

实现Callable<V>接口重写其中的call()方法V call()           计算结果,如果无法计算结果,则抛出一个异常。 注意事项:call()方法的返回值必须和Callable<v>中的返回值类型相同ExecutorsService :接口中的方法        Future<?> submit(Runnable task)        <T> Future<T> submit(Callable<T> task)示例:ExecutorService pool = Executors.newFixedThreadPool(2) ;    //下来使用ExecutorService(跟踪多个异步任务)一些方法    //使用submit(Runnable target):提交多个任务        pool.submit(new MyRunnable()) ;        pool.submit(new MyRunnable()) ;

多线程的匿名内部类方式

格式new 类名(具体类,抽象类)或接口(){//重写或实现方法}

示例

new Thread(){            @Override            public void run() {                //for循环                for(int x = 0 ; x <100 ; x ++){                    System.out.println(Thread.currentThread().getName()+":"+x);                }            }        }.start() ;//启动线程        //Runnable接口的方式new Thread(new Runnable() {            @Override            public void run() {                //for循环                for(int x = 0 ; x < 100 ; x ++){                    System.out.println(Thread.currentThread().getName()+":"+x);                }            }        }).start() ;

三:多线程的安全问题

  1. 概括:多个线程在抢占CPU的执行权,CPU的一点点时间片具有特性:原子性操作(最简单最基本)
  2. 检验方法
    (1)是否是多线程环境
    (2)是否存在数据共享
    (3)是否存在多条语句对共享数据进行操作
  3. 处理方式
    (1) 使用同步代码块:

    synchronized(同步锁对象){
    对共享数据进行操作的多条语句
    }

同步锁对象的类型(1)可以是Object类(2)如果静态同步方法:要通过反射获取Class类对象(当前类的字节码文件对象)(3)如果同步方法:对象为this

同步代码块的弊端:

  • 执行效率低
  • 容易出现死锁现象

(2)Lock锁
该类是一个接口

public class ReentrantLockextends Objectimplements Lock, Serializable//子实现类Lock lock = new ReentrantLock() ;//多态形式获取具体的对象void lock()           获取锁。 lock.lock();void unlock()           释放锁。 lock.unlock();

线程的通信,生产者消费者模式

常用方法(都为Object中的方法) void notify()           唤醒在此对象监视器上等待的单个线程。 void notifyAll()           唤醒在此对象监视器上等待的所有线程  void wait() ---调用该方法会立即释放锁          在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。

代码示例:

private boolean flag ; //默认没有数据,如果true,则说明有数据    //set(String name,int age)方法,产生数据数据    public synchronized void set(String name, int age) {        // 同步机制进行操作        // 判断有没有数据        if (this.flag) {            // 处于等待状态            try {                this.wait();// 阻塞式方法,立即释放锁 notify notifyAll();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        //设置学生数据        this.name = name ;        this.age = age ;        //修改标记        this.flag = true ;//有数据了        //通知t2:消费者线程来消费数据        this.notify() ;//唤醒等待这种状态...    }    public synchronized void get(){            if(!this.flag){                try {                    this.wait() ;//调用的时候,会立即释放锁                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            //输出语句            System.out.println(this.name+"---"+this.age);            //修改标记            this.flag = false ;//消费者线程            //通知对方(t1线程),消费者线程没有数据类,赶紧来消费            this.notify() ;//唤醒t1线程....    }}

四:线程组

public ThreadGroup(String name)                 构造一个新线程组----该方法可自定义线程名称(所有线程若未设置,默认为main)public Thread(ThreadGroup group,Runnable target ,String name)                 分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,并作为 group 所引用的线程组的一员。ThreadGroup getThreadGroup()           返回该线程所属的线程组。  String getName()           返回此线程组的名称。 

五:线程池

接口Executor执行已提交的 Runnable 任务的对象。接口ExecutorService是Executor的子接口ExecutorService的子实现对象的的创建Executor中的方法public static ExecutorService newFixedThreadPool(int nThreads)           创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。示例: //ExecutorService pool = Executors.newFixedThreadPool(2) ;Future<?> submit(Runnable task)           提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。void shutdown()           启动一次顺序关闭,执行以前提交的任务,但不接受新任务。 

六.定时器

Timer类public void schedule(TimerTask task,Date time)            安排在指定的时间执行指定的任务public void schedule(TimerTask task, long delay)           在多少毫秒后执行指定任务public void schedule(TimerTask task, long delay, long period)            在多少毫秒后,执行任务,并且每个多少毫秒重复执行public void cancel()             终止此计时器,丢弃所有当前已安排的任务