多线程问题总结

来源:互联网 发布:suse 11 yum 编辑:程序博客网 时间:2024/05/29 18:38

多线程

进程与线程的区别?

:进程是所有线程的集合,每一个线程是进程中的一条执行路径,线程只是一条执行路径。

为什么要用多线程?

 :提高程序效率

多线程创建方式?

  :继承ThreadRunnable接口。

是继承Thread类好还是实现Runnable接口好?

:Runnable接口好,因为实现了接口还可以继续继承。继承Thread类不能再继承。

你在哪里用到了多线程?

:主要能体现到多线程提高程序效率。

举例:分批发送短信、迅雷多线程下载等。

什么是多线程安全?

答:当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。做读操作是不会发生数据冲突问题。

如何解决多线程之间线程安全问题?

答:使用多线程之间同步或使用锁(lock)

为什么使用线程同步或使用锁能解决线程安全问题呢?

答:将可能会发生数据冲突问题(线程不安全问题),只能让当前一个线程进行执行。被包裹的代码执行完成后释放锁,让后才能让其他线程进行执行。这样的话就可以解决线程不安全问题。

什么是多线程之间同步?

:当多个线程共享同一个资源,不会受到其他线程的干扰。

什么是同步代码块?

:就是将可能会发生线程安全问题的代码,给包括起来。只能让当前一个线程进行执行,被包裹的代码执行完成之后才能释放所,让后才能让其他线程进行执行。

多线程同步的分类?

1.使用同步代码块?

synchronized(同一个数据){

 可能会发生线程冲突问题

}

     private Object mutex = new Object();//自定义多线程同步锁

    public void sale() {

        synchronized (mutex) {

            if (trainCount > 0) {

try {

                    Thread.sleep(10);

                } catch (Exceptione) {

                }

                System.out.println(Thread.currentThread().getName() +",出售 第" + (100 -trainCount + 1) + "张票.");

                trainCount--;           }

        }

    }

 

2.使用同步函数

在方法上修饰synchronized 称为同步函数

public synchronized void sale() {

            if (trainCount > 0) {

try {

                    Thread.sleep(40);

                } catch (Exceptione) {

                }

                System.out.println(Thread.currentThread().getName() +",出售 第" + (100 -trainCount + 1) + "张票.");

                trainCount--;

            }

    }

 

3.静态同步函数

方法上加上static关键字,使用synchronized 关键字修饰 为静态同步函数

静态的同步函数使用的锁是  该函数所属字节码文件对象

同步代码块与同步函数区别?

答:

同步代码使用自定锁(明锁)

同步函数使用this锁

同步函数与静态同步函数区别?

注意:有些面试会这样问:例如现在一个静态方法和一个非静态静态怎么实现同步?

答:

同步函数使用this锁

静态同步函数使用字节码文件,也就是类.class

什么是多线程死锁?

答:

同步中嵌套同步,无法释放锁的资源。

解决办法:同步中尽量不要嵌套同步

Wait()与Notify ()区别?

Wait让当前线程有运行状态变为等待状态,和同步一起使用

Notify 唤醒现在正在等待的状态,和同步一起使用

Wait()与sleep()区别?

对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。

sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。

在调用sleep()方法的过程中,线程不会释放对象锁。

而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备

获取对象锁进入运行状态。

Lock与synchronized区别?

Lock 接口可以尝试非阻塞地获取锁 当前线程尝试获取锁。如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁。
*Lock 接口能被中断地获取锁 与 synchronized 不同,获取到锁的线程能够响应中断,当获取到的锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。

Lock 接口在指定的截止时间之前获取锁,如果截止时间到了依旧无法获取锁,则返回。

Condition用法

 Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能,

代码:

Condition condition = lock.newCondition();

res. condition.await();  类似wait

res. Condition. Signal() 类似notify

Signalall notifyALL

 

如何停止线程?

  1.  使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

    2.  使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。

3.  使用interrupt方法中断线程。 线程在阻塞状态

什么是守护线程

Java中有两种线程,一种是用户线程,另一种是守护线程。

 当进程不存在或主线程停止,守护线程也会被停止。

 使用setDaemon(true)方法设置为守护线程

join()方法作用

join作用是让其他线程变为等待,只有当前线程执行完毕后,等待的线程才会被释放。

线程三大特性

多线程有三大特性,原子性、可见性、有序性

原子性:保证数据一致性,线程安全。

可见性:对另一个线程是否课件

有序性:线程之间执行有顺序

说说Java内存模型

共享内存模型指的就是Java内存模型(简称JMM),JMM决定一个线程对共享变量的写入时,能对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。

 

什么是Volatile作用

Volatile 关键字的作用是变量在多个线程之间可见。

什么是AtomicInteger

AtomicInteger原子类

什么是ThreadLoca

ThreadLocal提高一个线程的局部变量,访问某个线程拥有自己局部变量。

 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

ThreadLocal的接口方法

ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:

void set(Object value)设置当前线程的线程局部变量的值。

public Object get()该方法返回当前线程所对应的线程局部变量。

public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。

 

什么是线程池?

 线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求。然而,增加可用线程数量是可能的。线程池中的每个线程都有被分配一个任务,一旦任务已经完成了,线程回到池子中并等待下一次分配任务。

线程池作用

基于以下几个原因在多线程应用程序中使用线程是必须的:

  1. 线程池改进了一个应用程序的响应时间。由于线程池中的线程已经准备好且等待被分配任务,应用程序可以直接拿来使用而不用新建一个线程。

  2. 线程池节省了CLR 为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。

  3. 线程池根据当前在系统中运行的进程来优化线程时间片。

  4. 线程池允许我们开启多个任务而不用为每个线程设置属性。

  5. 线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。

  6. 线程池可以用来解决处理一个特定请求最大线程数量限制问题。

 

线程池四种创建方式

Java通过Executors(jdk1.5并发包)提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

 

说说JDK1.5并发包

名称

作用

Lock

Executors

线程池

ReentrantLock

一个可重入的互斥锁定 Lock,功能类似synchronized,但要强大的多。

Condition

 Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能,

 

ConcurrentHashMap

分段HasMap

AtomicInteger

原子类

BlockingQueue

 

BlockingQueue 通常用于一个线程生产对象,而另外一个线程消费这些对象的场景

ExecutorService

 

执行器服务

 

 

原创粉丝点击