多线程

来源:互联网 发布:excel数据透视表命名 编辑:程序博客网 时间:2024/06/06 02:14

多线程

多线程:程序的执行路径有多条

单线程:程序的执行路径只有一条.

 

面试题:Jvm,java虚拟机是多线程程序吗?

         答:是多线程程序,由于java虚拟机中自带一个垃圾回收器,来确保程序不会轻易的造成内存溢出!

         至少开启两条子线程:

                   1)当前程序在执行代码的时候,会开启main:主线程.

2)垃圾回收器会开启一个垃圾回收线程,来确保程序不会内存异常,将没用的变量或者没有更多引用的对象来回收掉.

 

如何实现多线程程序?

         1)要实现多线程程序,必须创建一个进程.

         2)创建进程需要调用系统资源进行创建,但是Java语言不能直接调用系统资源.

         3)C/C++语言可以创建系统资源,然后使用Java语言调用C/C++已经封装好的东西.

         4)Java---->类:Thread类.

 

并发和并行:

         并发:指的是同一个时间点.

         并行:指的是同一个时间段.

 

多线程程序的实现方式1:

         1)自定义一个类:MyThread继承自Thread类

         2)在MyThread类中重写Thread类中的run()方法.

         3)在主线程中,创建该类的实例对象,启动线程--- >调用start()方法.

                 

         为什么重写run()方法: run方法里面执行的耗时的操作:线程睡眠,线程等待,循环语句等.

 

如何获取线程的名称:

         publicfinal String getName() 返回线程的名称.

         设置线程名称:

         publicfinal void setName(String name) 改变线程名称,使之与参数name相同

 

public final int getPriority() 返回线程的优先级

         默认优先级:5

Java.lang.Thread:

         publicstatic final int MAX_PRIORITY 10  :最大优先级

         publicstatic final int MIN_PRIORITY 1   :最小优先级

         publicstatic final int NORM_PRIORITY 5  :默认优先级

         优先级大的抢占到CPU的执行权大,但并不代表一定能抢到,因为线程的执行具有随机性.

         给线程设置优先级:setPriority();

 

public static void yield() 暂停当前正在执行的线程对象,并执行其他线程

         暂停当前线程执行其他线程,并不保证另一个线程就一定能抢占到CPU的执行权.

 

public final void join()

                            throwInterruptedException 等待该线程终止(必须先启动线程)

 

线程睡眠:

         publicstatic void sleep(long millis)

                            ThrowsInterruptedException 在指定的毫秒数内让正在执行的线程休眠(暂停执行)    

 

线程停止:

         publicfinal void stop() : 强迫线程停止执行

         publicvoid interrupt() 中断线程, 表示中断线程一种状态

 

public final void setDaemon(boolean on) on指定true,就是设置守护线程.

         将该线程标记为守护线程或者用户线程,当正在运行的线程都是守护线程时,java虚拟机退出.          

         该方法必须在启动线程前调用.

         Jvm自动退出,对于主线程的数据如果直接输出完毕,对于两个守护线程不会立即消失,jvm等会就自动退出.

 

多线程实现的第二种方式:(实际开发中第二种比第一种应用更为广泛)

         开发步骤:

1)        自定义一个类MyRunnable,该类实现Runnable接口

2)        实现该接口中的run()方法.

3)        在主线程中创建该类的实例对象

4)        创建Thread类对象,将3)创建的对象作为参数进行传递

5)        分别启动线程

 

第二种方式优于第一种方式,采用Java设计原则:数据分离原则,而第一种单继承具有局限性.

 

 

面试题:多线程的实现方式有几种,分别是什么?

         答:三种方式

                   1)继承Thread类2)实现Runnable接口3)实现Callable接口

 

         继承Thread类:

                   1)自定义一个类:MyThread继承自Thread类

                  2)在MyThread类中重写Thread类中的run()方法.

                  3)在主线程中,创建该类的实例对象,启动线程--- >调用start()方法.

 

         实现Runnable接口:

1)                 自定义一个类MyRunnable,该类实现Runnable接口

2)        实现该接口中的run()方法.

3)        在主线程中创建该类的实例对象

4)        创建Thread类对象,将3)创建的对象作为参数进行传递

5)        分别启动线程

 

         实现Callable接口: 线程池利用Executors工厂类来进行ExecutorService对象的创建(线程池指定当前线程池中有多个线程)

利用submit(Runnabletarget) 提交异步任务

submit(Callable target) 提交异步任务

实现接口中的call():

结束线程池shutdown();

 

 

如何解决多线程的安全问题:

         检验多线程安全问题的标准(判断一个多线程程序是否存在安全问题)

                   1)当前是否是一个多线程环境

                   2)多线程环境是否有共享数据

                   3)是否有多条语句对共享数据进行操作

 

将多条语句对共享数据进行操作的代码用代码块包起来

         Java的同步机制:

         使用同步代码块:synchronized(同步锁对象){

         多条语句对共享数据的操作;

}

 

同步锁对象:应该每一个线程都要使用这个锁对象(同步锁):可以理解为门的开和关

使用同步代码块可以解决线程安全问题.

 

同步锁对象可以是什么样的对象

         可以是Object类型,任意的java类

 

同步锁对象:

         1)可以Object类型以及任意java类型对象

         2)如果一个方法进来之后是一个同步代码块,那么同步代码块可以演变成一个同步方法

         3)如果是一个静态的同步方法,锁对象是当前类名class属性:类名.class(反射机制:获取一些类的字节码文件对象Class类对象).

 

面试题:

         wait()线程等待,notify()唤醒单个线程,notifyAll()唤醒所有线程,这三个方法为什么不定义到Thread类中实现呢?而是定义在Object类中?

线程中会存在安全问题,并且解决线程安全问题使用的同步代码块或者同步方法来解决,同步代码块来解决线程安全问题,就存在同步锁对象,谁能代表同步锁对象(Object以及任意的Java类),把它定义到Object类中;

 

线程安全的类有哪些?

                 Vector

                StringBuffer

                Hashtable


Lock锁

Lock是一个接口,它使用的是ReentrantLock子实现类

 

Public void lock() 获取锁.

Public void unlock() 试图释放此锁.

 

使用同步机制可以解决多线程的安全问题,但是自身也会有弊端

         1)同步: 执行效率低,(每一个线程在抢占到CPU的执行权,就回去将门关闭,别的线程进不来)

         2)容易出现死锁现象

 

死锁现象:两个或两个以上的线程出现互相等待的情况,就会出现死锁.

 

等待唤醒机制(生产者线程和消费者线程)

机制:

生产者线程生产数据,如果本身就有数据,需要等待消费者线程输出数据,利用锁对象中的notify()唤醒(通知)消费者线程来输出数据

消费者线程输出数据,那么如果本身没有数据了,需要等待生产者线程产生数据,通知生产者线程生产数据.

 

反射机制:利用几个方法:               

Object类中的getClass()

Class类里面的forName(String className) ;类的全路径名称

类的class属性

获取当前类的字节码文件对象/Class类对象..

 

 

线程组表示一个线程的集合:Java允许一个线程中有多个线程

 

如何获取线程组名称:

         publicfinal ThreadGroup getThreadGroup() 返回该线程所属的线程组

         ThreadGrouptg1 = t1.getThreadGroup();

         publicfinal String getName() 返回此线程组的名称

         Stringname1 = tg1.getName();

         子线程默认的线程组名称:main线程

         所有的线程它的默认线程组名称就是main.

 

如何设置线程组名称:

         publicThreadGroup(String name) 构造一个新的线程组

         ThreadGrouptg = new ThreadGroup(“新的线程组名称”)

创建线程类对象,并且将线程组对象作为参数进行传递,就使用Thread类的构造方法:

publicThread(ThreadGroup group, Runnable target , String name)

Thread t1 = newThread (tg , my , ”线程1”);

 

JDk5新增了一个Executors工厂类来产生线程池,有以下方法:

         publicstatic ExecutorService newFixedThreadPool(int nThreads)

                   Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程

 

这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法

         ExecutorsService:接口中的方法

                   Future<?>submit(Runnable task)

                   <T>Future<T> submit(Callable<T> task)

 

线程池的好处:节约成本,

很多子线程调用完毕不会立即被回收掉,而是会回到线程池中被多次利用!

 

多线程程序的实现方式3: (很少用到)

         ExecuterService:接口中的方法

                   <T>Future<T> submit(Callable<T> task)

                   该返回值表示:异步计算的结果!

 

         //创建线程池对象,利用工厂类

                   ExecutorServiceThreadpool = Executors.newFixedThreadPool(2) ;

         //提交Callable任务(异步任务)

                   Threadpool.submit(newMyCallable()) ;//相当于线程中的start()方法

                   Threadpool.submit(newMyCallable()) ;

         //结束线程池

                   Threadpool.shutdown();

 

JavaSe中的定时器:

       Timer:

                常用的几个方法:

                         public voidschedule(TimerTask task,Date time)安排在指定的时间执行指定的任务

                         public voidschedule(TimerTask task, long delay)在多少毫秒后执行指定任务

                         public voidschedule(TimerTask task, long delay, long period)

                                   在多少毫秒后,执行任务,并且每个多少毫秒重复执行

                         public void cancel()终止此计时器,丢弃所有当前已安排的任务

 

多线程中匿名内部类的方式

                格式:

                new 类名(具体类,抽象类),接口(){

                                   重写/实现方法;

                }

 

  匿名内部类的本质:

                         继承了该类或者是实现该接口的子类对象!

 

多线线程的匿名内部类的方式

继承

new Thread(){

public void run(){

////

}

}.start();

 

接口的方式(这种方式多与继承方式)

new Thread(new Runnable()){

public void run(){

 ///

}

}.start() ;

 


        

 

 

        

原创粉丝点击