线程

来源:互联网 发布:牛股选股器源码 编辑:程序博客网 时间:2024/06/06 15:39

1、概述

这里写图片描述

这里写图片描述
这里写图片描述
这里写图片描述

(看最后一个图)
进程包含线程;线程是进程的一部分,是轻量级的进程,是不同的执行路径。
多线程:一条路径不能满足要求,另开辟一条路径。
真正的多线程是有多个cpu,有多核。cpu调度哪个程序哪段代码有个调度,调度过程中有个时间片(纳秒级别)。把线程a挂起,再执行线程b,时间片非常的短,看起来像是a和b同时在执行。
什么时候需要执行多线程?
main方法(主线程)执行的时候,还有后台默默执行的gc,这个就是多线程;
异常机制;

2、java实现多线程

就是一些类和接口
这里写图片描述
模拟多线程:

/** * 模拟龟兔赛跑 1、创建多线程  继承  Thread  +重写run(线程体) 2、使用线程: 创建子类对象 + 对象.start() ,这表示线程启动,线程启动不表示线程运行 (调用start()方法,加到线程组里面去了。 它内部由cpu去管控它,cpu去调用它。 而且不要去调用线程类的run方法,那不叫启动线程,而是方法调用。)    总之:想开辟一条新路径,必须调用start()方法,加到线程组里面,由cpu自己管控。 *  * @author Administrator * */public class Rabbit extends Thread {    @Override    public void run() {        //线程体        for(int i=0;i<100;i++){            System.out.println("兔子跑了"+i+"步");        }    }}class Tortoise extends Thread {    @Override    public void run() {        //线程体        for(int i=0;i<100;i++){            System.out.println("乌龟跑了"+i+"步");        }    }}public class RabbitApp {    /**     * @param args     */    public static void main(String[] args) {        //创建子类对象        Rabbit rab = new Rabbit();        Tortoise tor =new Tortoise();        //调用start 方法        rab.start(); //不要调用run方法,这个run方法是内部自己调用        //rab.run();        tor.start();        //tor.run();        //这里一共是5条路,加上main,后台的gc和异常。        for(int i=0;i<1000;i++){            System.out.println("main==>"+i);        }    }}

这里写图片描述

这种方式实现了静态代理模式。run方法不能对外声明异常

package com.bjsxt.thread.create;/** * 静态代理 设计模式 * 1、真实角色    * 2、代理角色: 持有真实角色的引用  (婚介忙前忙后,但结婚的人还是你) * 3、二者 实现相同的接口  (你租房子找中介公司、你结婚找婚介) *  * @author Administrator * */public class StaticProxy {    /**     * @param args     */    public static void main(String[] args) {        //创建真实角色,这里没有新增方法,就可以用接口        Marry you =new You();        //创建代理角色 + 真实角色的引用(这里可以用set和get方法,也可以用构造器)        WeddingCompany company =new WeddingCompany(you);        //执行任务        company.marry();    }}//接口interface Marry{    //void marry();可以省略    public abstract void marry();}//真实角色class You implements Marry{    @Override    public void marry() {        System.out.println("you and  嫦娥结婚了....");    }}//代理角色class WeddingCompany implements Marry{    private Marry you;    public WeddingCompany() {    }    public WeddingCompany(Marry you) {        this.you = you;    }    //注意是私有的    private void before(){        System.out.println("布置猪窝....");    }    private void after(){        System.out.println("闹玉兔....");    }    @Override    public void marry() {        before();        you.marry();        after();    }}

Thread类实现了Runnable接口,Thread类就是代理角色,我们创建一个真实角色就可以了。
真实角色实现Runnable接口+Thread(Runnable target)代理持有真实角色的引用 = 符合代理模式
源码中:run()方法,如果target!=null,就执行target的run()方法。
代理可以有多个,表示资源可以共享

package com.bjsxt.thread.create;/** * 方便共享资源 * @author Administrator * */public class Web12306 implements Runnable {    private int num =50;    @Override    public void run() {        while(true){            if(num<=0){                break; //跳出循环            }            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);        }    }    public static void main(String[] args) {        //真实角色        Web12306 web = new Web12306();        //代理        Thread t1 =new Thread(web,"路人甲");        Thread t2 =new Thread(web,"黄牛已");        Thread t3 =new Thread(web,"攻城师");        //启动线程        t1.start();        t2.start();        t3.start();    }}

创建多线程总结:
这里写图片描述

这里写图片描述

package com.bjsxt.thread.create;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * 使用Callable创建线程 * @author Administrator * */public class Call {    public static void main(String[] args) throws InterruptedException, ExecutionException {        //创建线程        ExecutorService  ser=Executors.newFixedThreadPool(2);        Race tortoise = new Race("老不死",1000);        Race rabbit = new Race("小兔子",500);        //获取值        Future<Integer> result1 =ser.submit(tortoise) ;        Future<Integer> result2 =ser.submit(rabbit) ;        Thread.sleep(2000); //2秒        tortoise.setFlag(false); //停止线程体循环        rabbit.setFlag(false);        int num1 =result1.get();        int num2 =result2.get();        System.out.println("乌龟跑了-->"+num1+"步");        System.out.println("小兔子跑了-->"+num2+"步");        //停止服务         ser.shutdownNow();    }}class Race implements Callable<Integer>{    private String name ; //名称    private long time; //延时时间    private boolean flag =true;    private int step =0; //步    public Race() {    }       public Race(String name) {        super();        this.name = name;    }    public Race(String name,long time) {        super();        this.name = name;        this.time =time;    }    @Override    public Integer call() throws Exception {        while(flag){            Thread.sleep(time); //延时            step++;        }        return step;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public long getTime() {        return time;    }    public void setTime(long time) {        this.time = time;    }    public boolean isFlag() {        return flag;    }    public void setFlag(boolean flag) {        this.flag = flag;    }    public int getStep() {        return step;    }    public void setStep(int step) {        this.step = step;    }}

3、线程状态

这里写图片描述

创建状态:new一下即可
就绪状态:调用start就进入就绪了
运行状态:cpu调度了

终止:线程体执(run方法)行完毕。 下面看线程怎么停止
这里写图片描述

这里写图片描述

package com.bjsxt.thread.status;public class StopDemo01 {    /**     * @param args     */    public static void main(String[] args) {        Study s =new Study();        new Thread(s).start();        //外部干涉        for(int i=0;i<100;i++){            if(50==i){ //外部干涉                s.stop();            }            System.out.println("main.....-->"+i);        }    }}class Study implements Runnable{     //1)、线程类中 定义 线程体使用的标识       private boolean flag =true;    @Override    public void run() {        //2)、线程体使用该标识        while(flag){            System.out.println("study thread....");        }    }    //3)、对外提供方法改变标识    public void stop(){        this.flag =false;    }}

这里写图片描述
阻塞:

join:合并线程. (等合进来的运行完了。)

package com.bjsxt.thread.status;/** * join:合并线程 * @author Administrator * */public class JoinDemo01 extends Thread {    /**     * @param args     * @throws InterruptedException      */    public static void main(String[] args) throws InterruptedException {        JoinDemo01 demo = new JoinDemo01();        Thread t = new Thread(demo); //新生        t.start();//就绪        //cpu调度 运行        for(int i=0;i<1000;i++){            if(50==i){                t.join(); //main阻塞...    等于50的时候,让demo执行完毕,再执行main线程            }            System.out.println("main...."+i);        }    }    @Override    public void run() {        for(int i=0;i<1000;i++){            System.out.println("join...."+i);        }    }}

yield:暂停自己的线程(后面可能还会被调度),(静态方法)(写在谁的线程体里面就暂定谁) (让合进来的运行一会儿)

package com.bjsxt.thread.status;public class YieldDemo01 extends Thread {    /**     * @param args     */    public static void main(String[] args) {        YieldDemo01 demo = new YieldDemo01();        Thread t = new Thread(demo); //新生        t.start();//就绪        //cpu调度 运行        for(int i=0;i<1000;i++){            if(i%20==0){                //暂停本线程 main                Thread.yield();            }            System.out.println("main...."+i);        }    }    @Override    public void run() {        for(int i=0;i<1000;i++){            System.out.println("yield...."+i);        }    }}

sleep:休眠,(静态方法)不释放锁。
倒计时:

package com.bjsxt.thread.status;import java.text.SimpleDateFormat;import java.util.Date;/** * 倒计时 * 1、倒数10个数,一秒内打印一个 * 2、倒计时 * @author Administrator * */public class SleepDemo01 {    /**     * @param args     * @throws InterruptedException      */    public static void main(String[] args) throws InterruptedException {        Date endTime =new Date(System.currentTimeMillis()+10*1000);        long end =endTime.getTime();        while(true){            //输出            System.out.println(new SimpleDateFormat("mm:ss").format(endTime));  //format格式化为字符串,parse转换为日期            //等待一秒,顺序也可以放在下面            Thread.sleep(1000);            //构建下一秒时间            endTime =new Date(endTime.getTime()-1000);            //10秒以内 继续 否则 退出            if(end-10000>endTime.getTime()){                break;            }        }    }    public static void test1() throws InterruptedException{        int num =10;        while(true){            System.out.println(num--);            Thread.sleep(1000); //暂停            if(num<=0){                break;            }        }    }}

网络延迟:

package com.bjsxt.thread.status;/** * Sleep模拟 网络延时  线程不安全的类 * @author Administrator * */public class SleepDemo02 {    /**     * @param args     */    public static void main(String[] args) {        //真实角色        Web12306 web= new Web12306();        Web12306 web2 = new Web12306();        //代理        Thread t1 =new Thread(web,"路人甲");        Thread t2 =new Thread(web,"黄牛已");        Thread t3 =new Thread(web,"攻城师");        //启动线程        t1.start();        t2.start();        t3.start();    }}class Web12306 implements Runnable {    private int num =50;    @Override    public void run() {        while(true){            if(num<=0){                break; //跳出循环            }            try {                Thread.sleep(500);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);        }    }}

线程状态:
这里写图片描述

设置优先级/** * 优先级:概率,不是绝对的先后顺序   MAX_PRIORITY  10   NORM_PRIORITY 5 (默认)   MIN_PRIORITY  1   setPriority()   getPriority() * @author Administrator * */

4、线程同步:

这里写图片描述
java.util.Hashtable - 线程安全的,同步的
StringBuffer – 也是线程安全的,使用了synchronized。这个关键字就是锁,任何线程访问这个方法,先获得这个方法的锁,锁住了门一关别人就访问不了
等线程锁释放了,别的锁才能进来。线程体执行完毕,锁自然就释放了。
访问同一个资源才会有并发问题,访问不同的资源没事。
一般地线程不安全的效率比较高。
JDK的RunTime就是单例中饿汉

package com.bjsxt.thread.syn;public class SynDemo01 {    /**     * @param args     */    public static void main(String[] args) {        //真实角色        Web12306 web= new Web12306();        //代理        Thread t1 =new Thread(web,"路人甲");        Thread t2 =new Thread(web,"黄牛已");        Thread t3 =new Thread(web,"攻城师");        //启动线程        t1.start();        t2.start();        t3.start();    }}/** * 线程安全的类 * @author Administrator * */class Web12306 implements Runnable {    private int num =10;    private boolean flag =true;    @Override    public void run() {        while(flag){            test5();        }    }    //线程不安全 锁定范围不正确    public void test6(){        if(num<=0){            flag=false; //跳出循环            return ;        }         //a  b  c          synchronized(this){            try {                Thread.sleep(500); //模拟 延时            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);        }    }    //线程不安全  锁定资源不正确    public void test5(){        //a  b  c        synchronized((Integer)num){            if(num<=0){                flag=false; //跳出循环                return ;            }            try {                Thread.sleep(500); //模拟 延时            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);        }    }    //锁定范围不正确 线程不安全    //锁定范围小了    public void test4(){        //   c  1        synchronized(this){            //b            if(num<=0){                flag=false; //跳出循环                return ;            }        }        // b        try {            Thread.sleep(500); //模拟 延时        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(Thread.currentThread().getName()+"抢到了"+num--);    }//a -->1    //线程安全  锁定正确    public void test3(){        //a  b  c   abc进来只能是依次地等待        //锁定this,this指的是对象        synchronized(this){            if(num<=0){                flag=false; //跳出循环                return ;            }            try {                Thread.sleep(500); //模拟 延时            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);        }    }    //线程安全  锁定正确    public synchronized void test2(){        if(num<=0){            flag=false; //跳出循环            return ;        }        try {            Thread.sleep(500); //模拟 延时        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(Thread.currentThread().getName()+"抢到了"+num--);    }    //线程不安全    public void test1(){        if(num<=0){            flag=false; //跳出循环            return ;        }        try {            Thread.sleep(500);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(Thread.currentThread().getName()+"抢到了"+num--);    }}
package com.bjsxt.thread.syn;/** * 单例设计模式:确保一个类只有一个对象 这个对象由类内部创建,外部只能使用这一个对象(JVM只有一个吧,其它类都是对它的引用) GC.. * @author Administrator * */public class SynDemo02 {    /**     * @param args     */    public static void main(String[] args) {        JvmThread thread1 = new JvmThread(100);        JvmThread thread2 = new JvmThread(500);        thread1.start();        thread2.start();    }}class JvmThread extends Thread{    private long time;    public JvmThread() {    }    public JvmThread(long time) {        this.time =time;    }    @Override    public void run() {             System.out.println(Thread.currentThread().getName()+"-->创建:"+Jvm.getInstance(time));    }}/** * 单例设计模式(的套路) * 确保一个类只有一个对象 * 懒汉式  double checking(经典的双重检查) * 1、构造器私有化,避免外部直接创建对象 * 2、声明一个私有的静态变量 * 3、创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象 */class Jvm {    //声明一个私有的静态变量    private static Jvm instance =null;    //懒得去创建对象    //构造器私有化,避免外部直接创建对象    private Jvm(){    }    //对getInstance3的改进    //创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象    public static Jvm getInstance(long time){        // c d e  -->效率  提供 已经存在对象的访问效率(线程不需要等待)        if(null==instance){             // a b 。a创建了,b进来发现有对象了,就不必等其他线程拿到对象之后它才可以拿,b直接拿对象就行            synchronized(Jvm.class){                if(null==instance ){                    try {                        Thread.sleep(time); //延时 ,放大错误。才会加一个time                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    instance =new Jvm();                }            }      }//a      return instance;    }    //这里是同步块    public static Jvm getInstance3(long time){        //a b c d e  -->效率不高 c  存在对象也需要等待        //任何时候要获取对象,如果对象存在的话,那也要进下面的方法,也要等待。锁定的是对象,线程b必须等线程a拿到对象之后才可以拿对象,有了一个等待的时间        //这里不能用this,因为静态方法里面没有this        synchronized(Jvm.class){            if(null==instance ){                try {                    Thread.sleep(time); //延时 ,放大错误                } catch (InterruptedException e) {                    e.printStackTrace();                }                instance =new Jvm();            }            return instance;        }    }    //这里是同步方法    public static synchronized Jvm getInstance2(long time){        if(null==instance ){            try {                Thread.sleep(time); //延时 ,放大错误            } catch (InterruptedException e) {                e.printStackTrace();            }            instance =new Jvm();        }        return instance;    }    //问题:单线程里面new出来的始终是一个对象,多线程的话就要加synchronized    public static Jvm getInstance1(long time){        if(null==instance ){            try {                Thread.sleep(time); //延时 ,放大错误            } catch (InterruptedException e) {                e.printStackTrace();            }            //两个线程进来,就有可能创建两个对象            instance =new Jvm();        }        return instance;    }}
package com.bjsxt.thread.syn;/** * 单例创建的方式 * 1、懒汉式 * 1)、构造器私有化 * 2)、声明私有的静态属性 * 3)、对外提供访问属性的静态方法,确保该对象存在 *  * @author Administrator * */ //懒汉式public class MyJvm {    private static MyJvm instance;    private MyJvm(){    }    //多线程的难点:又要提高效率,又要注意安全    public static MyJvm getInstance (){        if(null==instance){ //提供效率            synchronized(MyJvm.class){                if(null==instance){ //安全                    instance =new MyJvm();                }            }        }        return instance;    }}/** * 饿汉式   1)、构造器私有化  * 2)、声明私有的静态属性,同时创建该对象 * 3)、对外提供访问属性的静态方法 * @author Administrator * */class MyJvm2 {    //这里是线程安全的,    //加载MyJvm2的时候instance就初始化    private static MyJvm2 instance =new MyJvm2();    private MyJvm2(){    }    public static MyJvm2 getInstance (){                return instance;    }}/** * 类在使用的时候加载 ,延缓加载时间 * @author Administrator * */class MyJvm3 { //对MyJvm2的改进,提升效率的    //内部类       //加载MyJvm3的时候不一定会加载JVMholder,只有用到的时候(这里是调用getInstance时)加载。不调用该方法,JVMholder永远不会被加载    //可以延缓加载时间    private static class JVMholder{        private static MyJvm3 instance =new MyJvm3();    }    private MyJvm3(){    }    public static MyJvm3 getInstance (){                return JVMholder.instance;    }}

死锁:过多的同步造成死锁
即:不给我钱我不给你货,你不给我货我就不给你钱
同一份资源,在线程A中用了,又在线程B中用了,就可能会造成死锁。互相不释放

package com.bjsxt.thread.syn;/** * 过多的同步方法可能造成死锁 * @author Administrator * */public class SynDemo03 {    /**     * @param args     */    public static void main(String[] args) {        Object g =new Object();        Object m = new Object();        Test t1 =new Test(g,m);        Test2 t2 = new Test2(g,m);        Thread proxy = new Thread(t1);  //多态不能调用新增方法        Thread proxy2 = new Thread(t2);        proxy.start();        proxy2.start();    }}class Test implements Runnable{    Object goods ;    Object money ;    public Test(Object goods, Object money) {        super();        this.goods = goods;        this.money = money;    }    @Override    public void run() {        while(true){            test();        }    }    public void test(){        synchronized(goods){            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            synchronized(money){            }        }        System.out.println("一手给钱");    }}class Test2  implements Runnable{    Object goods ;    Object money ;    public Test2(Object goods, Object money) {        super();        this.goods = goods;        this.money = money;    }    @Override    public void run() {        while(true){            test();        }    }    public void test(){        synchronized(money){            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            synchronized(goods){                }        }        System.out.println("一手给货");    }}

生产者消费者模式(不是设计模式,是解决多线程的问题)
如何解决死锁,看看生产者消费者模式。
先生产再消费,有东西了再消费,没有东西先生产(用的是同一份资源)
这里写图片描述

package com.bjsxt.thread.pro;/** 一个场景,共同的资源  生产者消费者模式 信号灯法 wait() :等待,释放锁  。 sleep 不释放锁 notify()/notifyAll():唤醒   他俩必须要与 synchronized一起使用 * @author Administrator * */public class Movie {    private String pic ;    //信号灯    //flag -->T 生产生产,消费者等待 ,生产完成后通知消费    //flag -->F 消费者消费 生产者等待, 消费完成后通知生产    private boolean flag =true;    /**     * 播放     * @param pic     */    public synchronized void play(String pic){        if(!flag){ //生产者等待            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        //开始生产        try {            Thread.sleep(500);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("生产了:"+pic);  //生产了左青龙        //生产完毕              this.pic =pic;        //通知消费        this.notify();        //生产者停下        this.flag =false;    }    public synchronized void watch(){        if(flag){ //消费者等待            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        //开始消费        try {            Thread.sleep(200);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("消费了"+pic);        //消费完毕        //通知生产        this.notifyAll();        //消费停止        this.flag=true;    }}

5、任务调度

这里写图片描述

import java.util.Date;import java.util.Timer;import java.util.TimerTask;/**    了解  Timer()   schedule(TimerTask task, Date time)   schedule(TimerTask task, Date firstTime, long period)   自学 quartz * @author Administrator * */public class TimeDemo01 {    /**     * @param args     */    public static void main(String[] args) {        Timer timer =new Timer();        timer.schedule(new TimerTask(){            @Override            public void run() {                System.out.println("so easy....");            }}, new Date(System.currentTimeMillis()+1000), 200);    }}
原创粉丝点击