博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程的实现及常用方法_DAY23
阅读量:7046 次
发布时间:2019-06-28

本文共 14695 字,大约阅读时间需要 48 分钟。

1:多线程(理解)

 (1)如果一个应用程序有多条执行路径,则被称为多线程程序。

       进程:正在执行的程序。

       线程:程序的执行路径,执行单元。

       单线程:如果一个应用程序只有一条执行路径,则被称为单线程程序。

       多线程:如果一个应用程序有多条执行路径,则被称为多线程程序。

 

       举例:迅雷下载,360的管理界面。

 

       单进程单线程:一个人点一桌菜

       单进程多线程:多个人点一桌菜

       多进程多线程:多个人点多桌菜

    (2)多线程程序实现的两种方案:(掌握 步骤我们一起写,代码你写)

       A:继承Thread类

           a:自定义类MyThread继承Thread类。

           b:重写run方法(),在这里面输出1-100的数据。

           c:创建测试类MyThreadTest,在测试类中创建MyThread类的多个对象。

           d:调用start() ,注意不是run()方法,此外线程开启必须在main方法中代码之前,因为main方法也是一个线程,里面的代码是顺序执行的。

 

           代码体现:

public class MyThread extends Thread {              public MyThread(){}              public MyThread(String name) {                  super(name);              }               public void run() {                  for(int x=1; x<=100; x++) {                     System.out.println(getName()+"---"+x);                  }              }           }            public class MyThreadTest {              public static void main(String[] args) {                  MyThread my1 = new MyThread("三国志");                  MyThread my2 = new MyThread("三国杀");                   //my1.setName("三国志");                  //my2.setName("三国杀");                   my1.start(); // 注意,调用的是start()方法,而不是run方法                  my2.start();              }           }
View Code

       B:实现Runnable接口(更好)

           a:自定义类MyRunnable实现Runnable接口。

           b:重写run方法(),在这里面输出1-100的数据。

           c:创建测试类MyThreadTest,在测试类中创建MyRunnable类的一个对象。

           d:在测试类创建Thread类的多个对象,并把MyRunnable类的一个对象作为构造参数传递。

             用到的构造器:public Thread(Runnable target,

                               String name)

           e:调用start()

 

           代码体现:  

public class MyRunnable implements Runnable {              public void run() {                  for(int x=1; x<=100; x++) {                     System.out.println(Thread.currentThread().getName()+"---"+x);                  }              }           }                     public class MyRunnableTest {              public static void main(String[] args) {                  MyRunnable my = new MyRunnable();                   Thread t1 = new Thread(my,"斗地主");                  Thread t2 = new Thread(my,"三国群英传2");                   t1.start();                  t2.start();              }           }
View Code

 (3)面试题:

        A:如何启动一个线程

       B:start()和run()方法的区别

       C:线程随机性原理

       D:线程的生命周期

       E:线程的安全问题是怎么产生的,以及是如何解决的?

       F:同步解决线程安全问题的方式有几种?

       G:同步代码块的锁对象是谁?同步方法的锁对象是谁?

       F:静态方法的锁对象是谁?

 (4)几个方法

       A、优先级(priority)  

           线程优先级代表了抢占CPU的能力。优先级越高,抢到CPU执行的可能性越大。(一般环境下效果不明显,优先级并非绝对的执行顺序。)

           优先级相关方法:

            public final void setPriority(int?newPriority) 优先级取值:1-10

            public final int getPriority()

例子:cn.itcast2.demo

package cn.itcast2;/* * 线程优先级: *         public final int getPriority()获取优先级 *         public final void setPriority(int newPriority)更改优先级 */public class Demo {    public static void main(String[] args) {        MyThread mt = new MyThread();        mt.setName("唐嫣");//        mt.setPriority(10);        System.out.println(mt.getPriority());                MyThread mt2 = new MyThread();        mt2.setName("柳岩");        mt2.setPriority(1);                mt.start();        mt2.start();    }}
View Code
package cn.itcast2;public class MyThread extends Thread {    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(getName()+":"+i);        }    }}
View Code

 

       B、暂停(yield) 

           暂停当前正在执行的线程对象,并执行其他线程。(效果不明显,如果想保证完成线程相互等待一次执行,需要使用到后边的等待唤醒机制 )

           线程礼让相关方法:

           public static void yield()

 例子:cn.itcast2.demo4   cn.itcast2.MyThread1.java

package cn.itcast2;/* * 线程礼让: *         暂停当前正在执行的线程对象,并执行其他线程 *         public static void yield() */public class Demo4 {    public static void main(String[] args) {                MyThread1 myThread = new MyThread1();        myThread.setName("唐嫣");        MyThread1 myThread2 = new MyThread1();        myThread2.setName("高圆圆");                myThread.start();        myThread2.start();    }    }
View Code
package cn.itcast2;public class MyThread1 extends Thread {    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(getName()+":"+i);            Thread.yield();        }    }}
View Code

 

       C、加入(join) cn.itcast2.demo3

           等待该线程终止。 即当前线程等待调用join方法的线程执行结束后再执行

           public final void join() throws InterruptedException 

package cn.itcast2;/* * 加入线程: *         public final void join()                throws InterruptedException  等待该线程终止。 即当前线程等待调用join方法的线程执行结束后再执行 */public class Demo3 {    public static void main(String[] args) throws Exception {                MyThread myThread = new MyThread();        myThread.setName("唐嫣");        MyThread myThread2 = new MyThread();        myThread2.setName("高圆圆");                myThread.setPriority(1);                myThread.start();                myThread2.start();        myThread2.join(); //等待myThread2线程执行完以后,main方法所在的线程才会执行        for (int i = 0; i < 100; i++) {            System.out.println(Thread.currentThread().getName()+":"+i);        }    }}
View Code
package cn.itcast2;public class MyThread extends Thread {    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(getName()+":"+i);        }    }}
View Code

 

       D、守护线程 

          设置守护线程的方法:

          没有设置为守护线程的线程执行完毕,则程序停止运行

           public final void setDaemon(boolean on)

           注意:该方法必须在线程启动前调用

例子: cn.itcast2.demo5

package cn.itcast2;/* * 守护线程: *         设置守护线程的方法: *         public final void setDaemon(boolean on) *              注意:该方法必须在线程启动前调用 */public class Demo5 {    public static void main(String[] args) {        MyThread1 myThread = new MyThread1();        myThread.setName("唐嫣");        MyThread1 myThread2 = new MyThread1();        myThread2.setName("高圆圆");                myThread.setDaemon(true); //设置守护线程        myThread2.setDaemon(true);//设置守护线程                myThread.start();        myThread2.start();        for (int i = 0; i < 10; i++) {  //主线程没有设置为守护线程,主线程执行完毕,则程序停止运行            System.out.println(Thread.currentThread().getName()+":"+i);        }    }}
View Code
package cn.itcast2;public class MyThread1 extends Thread {    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(getName()+":"+i);            Thread.yield();        }    }}
View Code

 

       E、线程睡眠(sleep) 

           指定线程休眠一定时间,进入等待状态。在该段时间结束后,线程重新可执行。

           线程休眠相关方法:

            public static void sleep(long?millis) throws InterruptedException

   例子:cn.itcast2.demo2

package cn.itcast2;/* * 线程休眠: *     public static void sleep(long millis) throws InterruptedException  将当前线程休眠,指定毫秒值 */public class Demo2 {    public static void main(String[] args) throws Exception {        System.out.println("我困了");                MyThread mt = new MyThread();        mt.start();                Thread.sleep(3000l);        System.out.println("我醒了");            }}
View Code
package cn.itcast2;public class MyThread extends Thread {    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(getName()+":"+i);        }    }}
View Code

 

       F、线程中断(interrupt) 

           中断线程。

              stop方法已过时,通常使用interrupt方法。

           中断线程相关方法:

              public void interrupt()   被中断的线程会报被中断异常,这时需要使用try/catch语句解决相关问题,线程后代码仍然可以继续执行

              public final void stop()  (已过时)  直接停止线程,线程后代码无法被执行

     例子:cn.itcast2.demo6   cn.itcast2.MyThread2

package cn.itcast2;/* * stop方法直接停止线程,方法过于暴力。直接导致sleep后的代码无法执行。 * 线程中断: *              public void interrupt()  抛出异常,处理异常,后边代码继续执行 */public class Demo6 {    public static void main(String[] args) throws Exception {                MyThread2 myThread = new MyThread2();        MyThread2 myThread2 = new MyThread2();                myThread.start();        myThread2.start();                Thread.sleep(3000);        myThread.stop();        myThread2.interrupt();    }}
View Code
package cn.itcast2;public class MyThread2 extends Thread {    @Override    public void run() {                System.out.println("我困了");        try {            Thread.sleep(10000l);        } catch (InterruptedException e) {            System.out.println("谁把我叫醒了,真烦!");        }                System.out.println("睡醒了");    }    }
View Code

 

 (5)案例:

       卖票案例。例子:cn.itcast3.demo  cn.itcast3.Ticket

 

package cn.itcast3;/* * 线程安全问题: *         多个窗口卖指定个数的票 *         3个窗口卖100张票 *         票:共享数据 *         窗口:线程 */public class Demo {    public static void main(String[] args) {                Ticket ticket = new Ticket();                Thread thread = new Thread(ticket,"唐嫣");        Thread thread2 = new Thread(ticket,"柳岩");        Thread thread3 = new Thread(ticket,"高圆圆");                thread.start();        thread2.start();        thread3.start();    }}
View Code
package cn.itcast3;/* * 票类(线程执行的目标):执行买票动作 */public class Ticket implements Runnable {    int number = 100; //应该放在成员变量的位置,实现三个对象的数据共享    Object o = new Object();        @Override    public void run() {                while(true) {            synchronized(o) {                            try {                    Thread.sleep(10);                } catch (InterruptedException e) {                    e.printStackTrace();                }                                //如果有票,就卖票                if(number>0) {                    //卖票                    System.out.println(Thread.currentThread().getName()+":"+number);                    number--;                }            }        }    }}
View Code

 

       线程安全问题:

           怎么产生的:

              A:多线程环境

              B:有共享数据

              C:多条语句操作共享数据

 

       怎么解决:

           把C步骤给锁起来。

 

       两种方案:

           a:同步代码块

               synchronized(锁对象) {

                  一个原子性操作

              }

           注意:几个线程需要使用相同的锁对象进行同步操作,使用不同的锁是无法完成同步操作的。

           例子:cn.itcast3.demo  cn.itcast3.Ticket

package cn.itcast3;/* * 线程安全问题: *         多个窗口卖指定个数的票 *         3个窗口卖100张票 *         票:共享数据 *         窗口:线程 */public class Demo {    public static void main(String[] args) {                Ticket ticket = new Ticket();                Thread thread = new Thread(ticket,"唐嫣");        Thread thread2 = new Thread(ticket,"柳岩");        Thread thread3 = new Thread(ticket,"高圆圆");                thread.start();        thread2.start();        thread3.start();    }}
View Code
package cn.itcast3;/* * 票类(线程执行的目标):执行买票动作 */public class Ticket implements Runnable {    int number = 100; //应该放在成员变量的位置,实现三个对象的数据共享    Object o = new Object();        @Override    public void run() {                while(true) {            synchronized(o) {                            try {                    Thread.sleep(10);                } catch (InterruptedException e) {                    e.printStackTrace();                }                                //如果有票,就卖票                if(number>0) {                    //卖票                    System.out.println(Thread.currentThread().getName()+":"+number);                    number--;                }            }        }    }}
View Code

 

           b:同步方法

              把synchronized添加到方法声明上。返回值前。例如:public synchronized void method() {}

              例子:cn.itcast4.demo  cn.itcast4.Ticket

package cn.itcast4;/* * 线程安全问题: *         多个窗口卖指定个数的票 *         3个窗口卖100张票 *         票:共享数据 *         窗口:线程 */public class Demo {    public static void main(String[] args) {                Ticket ticket = new Ticket();                Thread thread = new Thread(ticket,"唐嫣");        Thread thread2 = new Thread(ticket,"柳岩");        Thread thread3 = new Thread(ticket,"高圆圆");                thread.start();        thread2.start();        thread3.start();    }}
View Code
package cn.itcast4;/* * 票类(线程执行的目标):执行买票动作 *  * 同步方法: *         在方法上,返回值前,声明synchronized定义同步方法。 *         该方法的锁为所在对象。 */public class Ticket implements Runnable {    int number = 100;    Object o = new Object();        @Override    public void run() {                while(true) {            if(number%2==0) {  //当票数为偶数时                synchronized(this) {   //当前不变的对象,即ticket                                        try {                        Thread.sleep(10);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                                        //如果有票,就卖票                    if(number>0) {                        //卖票                        System.out.println(Thread.currentThread().getName()+":"+number);                        number--;                    }                }            }else {                method();            }        }    }        public synchronized void method() {  //在方法上,返回值前,声明synchronized定义同步方法。                                             //该方法的锁为所在对象。        try {            Thread.sleep(10);        } catch (InterruptedException e) {            e.printStackTrace();        }                //如果有票,就卖票        if(number>0) {            //卖票            System.out.println(Thread.currentThread().getName()+":"+number);            number--;        }    }}
View Code

 

           c.静态同步方法

               将方法所在类作为默认所,即XX.class

              例子:cn.itcast5.demo  cn.itcast5.Ticket

package cn.itcast5;/* * 线程安全问题: *         多个窗口卖指定个数的票 *         3个窗口卖100张票 *         票:共享数据 *         窗口:线程 */public class Demo {    public static void main(String[] args) {                Ticket ticket = new Ticket();                Thread thread = new Thread(ticket,"唐嫣");        Thread thread2 = new Thread(ticket,"柳岩");        Thread thread3 = new Thread(ticket,"高圆圆");                thread.start();        thread2.start();        thread3.start();    }}
View Code
package cn.itcast5;/* * 票类(线程执行的目标):执行买票动作 *  * 静态同步方法: *         在方法上,返回值前,声明static synchronized定义静态同步方法。 *         该方法的锁为所在的类对象。 */public class Ticket implements Runnable {    static int number = 100;    Object o = new Object();        @Override    public void run() {                while(true) {            if(number%2==0) {                synchronized(Ticket.class) {  //类对像                                        try {                        Thread.sleep(10);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                                        //如果有票,就卖票                    if(number>0) {                        //卖票                        System.out.println(Thread.currentThread().getName()+":"+number);                        number--;                    }                }            }else {                method();            }        }    }        public static synchronized void method() {  //类对像                try {            Thread.sleep(10);        } catch (InterruptedException e) {            e.printStackTrace();        }                //如果有票,就卖票        if(number>0) {            //卖票            System.out.println(Thread.currentThread().getName()+":"+number);            number--;        }    }}
View Code

 

(6)Java同步机制的优缺点:

            a:优点:解决了多线程安全问题

            b:缺点:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。对于一个简单操作,单线程速度更快。

 

(7)多线程的优缺点

        多线程并不提高某个程序的执行速度,仅仅是提高了CPU的使用率。

       图1:多线程示意图

       图2:多线程现率高

       图3:多线程状态图

   

2:单例设计模式(理解 面试)

(1)保证类在内存中只有一个对象。

(2)怎么保证:

       A:构造私有

       B:自己造一个对象

       C:提供公共访问方式

 (3)两种方式:

       A:懒汉式(面试)

           public class Student {

              private Student(){}

 

              private static Student s = null;

 

              public synchronized static Student getStudent() {

                  if(s == null) {

                     s = new Student();

                  }

                  return s;

              }

           }

 

 

       B:饿汉式(开发)

           public class Student {

              private Student(){}

 

              private static Student s = new Student();

 

              public static Student getStudent() {

                  return s;

              }

           }

 (4)JDK的一个类本身也是单例模式的。

       Runtime

转载地址:http://lxzol.baihongyu.com/

你可能感兴趣的文章
聊天机器人已死,为什么腾讯还要打造自己的智能客服?
查看>>
如何打造一流的查询引擎,构建优秀的数据仓库?
查看>>
想要高效上传下载?试试去中心化的Docker镜像仓库设计
查看>>
Java的序列化特性将要退出历史舞台了
查看>>
Netty 学习和进阶策略
查看>>
Leetcode 16. 3Sum Closest
查看>>
linux及git记录
查看>>
自制jq分页插件
查看>>
详解js变量声明提升
查看>>
【windows】win10正式版分享WiFi热点
查看>>
程序与文档
查看>>
独孤九剑(0x04) - 测试篇
查看>>
JS学习总结
查看>>
一个前端写的php博客系统--支持markdown哦
查看>>
Laravel Taggable 为你的模型添加打标签功能
查看>>
Erlang/Elixir: 使用 Edeliver 进行自动化的持续部署
查看>>
Nodejs检测端口是否被占用
查看>>
webpack入坑之旅(二)loader入门
查看>>
如何优雅高效地插入百度广告
查看>>
DbUtils应用在Android6.0中为什么会崩溃
查看>>