首页 > 代码库 > 多线程编程核心技术总结(读周志明书籍的总结)

多线程编程核心技术总结(读周志明书籍的总结)

多线程编程核心技术总结

 

1.Java多线程基本技能

1.1进程和线程的概念:

进程是独立的程序,线程是在进程中独立运行的子任务。

1.2使用多线程

1.2.1实现方法:继承Thread类,重写Runnable接口。

1.2.2线程安全问题:并发修改公共的实例变量,i++,i--

1.3线程Thread类的一些方法:

currentThread() 放回代码段正在被那个线程调用

isAlive() 判断线程是否处于活动状态

sleep() 使得当前线程退出CPU片段,等待获取锁

1.4停止线程

1.4.1使用interrupt()方法不是使线程马上停止执行,而是打了个暂停的标记。

this.interrupted():测试当前线程是否已经中断,this.isInterrupted():测试当前线程是否已经中断。

1.4.2停止线程常用方法--异常法(抛出异常)

1.4.3 在sleep()时,去interrupted。

1.4.4 yield()方法的作用是放弃当前的CPU资源,放弃多长时间不确定,立即加入到CPU的竞争中。

1.5线程优先级

优先级从1—10不等,设置用setPriority()方法,但是优先级具有随机性,优先级高的不一定先执行。

1.6守护线程

Java线程有两种,一种是守护线程(Daemon)另一是用户线程,垃圾回收线程就是典型的守护线程。守护线程为其它线程的运行提供便利,当其他线程都结束时,守护线程才与JVM一同结束工作。

 

2.对象及变量的并发访问

线程安全问题出现在“实例变量”中,如果是方法内部的私有变量,则不存在线程安全问题。

2.1synchronized同步方法

(1)Synchronized获得对象锁,那个线程先执行带synchronized关键字的方法;那个线程就持有该方法所属对象的锁,其它访问同一对象的线程就只能等待;

(2)只有共享资源的读写才需要做同步化;

(3)A线程先持有object对象的锁,B线程可以以异步的方式调用object对象的非synchronized方法。

A线程先持有object对象的锁,B线程如果调用object对象的synchronized方法,则需要等待,即同步。

(4) synchronized锁重入:synchronized方法内部调用本类其它的synchronized方法时,是永远可以得到锁的。

(5) 出现异常,锁自动释放。同步不具有继承性。

2.2 synchronized同步语句块

Synchronized方法是对当前对象进行加锁,而synchronized代码块是对某一个对象加锁。Synchronized方法效率太低,synchronized代码块更加细粒化

(1)synchronized同步方法

1)对其他同一对象的synchronized方法或synchronized(this)同步代码块呈阻塞状态。

2)同一时间只有一个线程可以执行synchronized同步方法中的代码

(2)synchronized(this)同步代码块

1)对其他同一对象的synchronized方法或synchronized(this)同步代码块呈阻塞状态。

2)同一时间只有一个线程可以执行synchronized(this)同步代码块中的代码

(3)synchronized(对象x)同步代码块

1)在多个线程持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(对象x)同步代码块;

2)持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(对象x)同步代码块。

对象监视器必须是同一个对象才是同步的,否则是异步调用。

 

(4)静态同步Synchronized方法与Synchronized(class)代码块

Synchronized关键字用于static方法上时,如果这样写,那是对当前类进行加锁与Synchronized(class)代码块作用一致。Synchronized关键字用于非static方法上时,如果这样写,那是对当前类的对象进行加锁。

 

(5)多线程死锁:比如两个对象持有对象锁,在同步方法(或者块)内部同时请求另一个对象的对象锁。

(6)只要对象不变,即使对象属性被改变,运行的结果还是同步的。

2.3 volatile修饰属性

(1) volatile强制从公共堆栈中取得变量的值,而不是从线程私有数据栈取得变量值。

(2) volatile与synchronized关键字比较

1)volatile是线程同步的轻量级实现,其性能肯定比synchronized要好,并且volatile只能修饰变量,而synchronized可修饰方法、代码块。

2)多线程访问volatile不会发生阻塞,而synchronized会出现阻塞。

3) volatile保证数据的可见性,不保证原子性;而synchronized既可以保证原子性也间接保证可见性。

4) volatile解决变量在多线程之间的可见性,而synchronized解决的是多线程之间访问资源的同步性。线程安全包括原子性和可见性。

 

线程工作内存中: read  (load  use asign) store write 括号中的三步非原子性。

 

(3)synchronized可以保证同一时刻,只有一个线程可以执行某一个方法或某一个代码块。包括两个特征:互斥性和可见性。同步synchronized不仅可以解决一个线程看到对象处于不一致状态,还可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果。

3.线程间通信

3.1等待通知机制的实现

(1)Wait()/notify()/notifyAll()都是Object类的方法。调用这些方法之前需先获得对象锁。调用wait()方法的线程将会在该代码行处停止且释放锁,进入“预执行队列”被唤醒之后才有机会获取锁。执行Notify()方法的线程不会释放锁,随机唤醒一个正在等待“共享资源”的线程,如果一个阻塞的共享资源的线程都没有,则忽略。notifyAll()唤醒全部的,等本线程退出CPU,这些线程去争抢锁。

(2)每个锁对象都有两个队列,一个是就绪队列(可运行),一个是阻塞队列(要唤醒之后才是可运行)。

(3)sleep方法不释放锁。遇到异常会释放锁。

(4)wait(long)等待long时间,如果没有其他线程来唤醒它,自动唤醒。使用wait和notify时要注意wait条件发生变化,容易造成程序逻辑混乱。

(5)生产者、消费者模式实现:生产者中Value值不为空,则lock.wait();否则进行设置值的操作,然后lock.notify()唤醒消费者。消费者中value为空,则lock.wait(),否则进行取值操作,然后lock.notify()唤醒生产者。

多生产-单消费:使用notify会造成假死,使用notifyAll来解决。

(6)通过管道流来进行线程间通信,PipedInputStream,PipedOutputStream,PipedReader和PipedWriter。最后outputStream.connect(inputStream)

3.2方法join的使用

(1)方法join是使所属的线程对象x执行run方法的任务,而使当前线程z进行无限期的阻塞,等待线程销毁后在继续执行z后面的代码。Join过程中,如果当前线程被中断,则出现异常。

(2)join(long)内部是使用wait来实现的,所以会释放锁。Sleep却不会。

3.3类ThreadLocal的使用

(1)这个类解决每个线程都有自己的共享变量的问题。

ThreadLocal t=new ThreadLocal(); 这个对象有get()、set()方法。解决的是变量在不同线程间的隔离性。也就是不同线程可以有自己的值,并放在ThreadLocal中保存。

(2)InheritableThreadLocal类,可以在子线程中取得父线程继承下来的值。

 

4.Lock的使用

4.1 ReentrantLock类,目的是为了实现同步异步,比synchronized更加灵活。

(1)首先 Lock lock =new ReentrantLock(); 然后在需要同步的方法中的首行使用lock.lock(),方法的结束行使用lock.unlock()。效果和使用synchronized关键字一样。当然也可以去锁一部分代码块。

(2)Condition对象实现指定线程的等待、通知,相当于wait和notify升级版。Synchronized相当于只有一个condition对象。

首先 Lock lock =new ReentrantLock();

     Condition condition=new Condition();

在方法中先调用lock.lock()获得同步监视器(否则报异常),然后用condition.await()来让这个线程进入阻塞队列。

(3)使用Condition实现等待通知

conditionA.await()进入阻塞,conditionA.signal()唤醒指定的这个线程。

signalAll()相当于notifyAll。

(4)使用多个Condition实现通知部分线程

  Condition conditionA=new Condition();

  Condition conditionB=new Condition();

conditionA.await()只有conditionA.signal(All)可以唤醒

(5)也可以实现生产者消费者模式,lock.lock()和signall方法。

(6)公平锁:线程获取的顺序是按照线程加锁的顺序来分配的,先来先得。非公平锁,采用抢占机制,随机获得锁。reentranLock类默认情况使用的是非公平锁。

(7)int getHoldCount()返回当前线程调用lock()方法的次数。

(8)int getQueueLength()返回正在等待获取此锁定的线程估计数。

(9)int getWaitQueueLength(Condition condition )返回等待此锁定相关的给定条件condition的线程估计数。

(10)boolean hasQueuedThread(thread) 查询指定线程是否在等待此锁,

方法boolean hasWaiters(Condition condition) 作用是查询是否有线程正在等待与此锁定有关的condition条件。

(11)可使用多个Condition对象实现业务的顺序执行。交替链接唤醒。

A方法中 conditionA.await()---conditionB.signalAll--

B方法中 conditionB.await()---conditionC.signalAll--

C方法中 conditionC.await()---conditionA.signalAll--

 

4.2ReentrantReadWriteLock类

读锁是共享锁,写锁是排他锁,读读共享是异步的,写读、写写都是互斥的同步的。

(1)ReentrantReadWriteLock类实现读读共享

ReentrantReadWriteLock lock=new ReentrantReadWriteLock();

 lock.readLock().lock();

……代码段

lock.readLock().unlock()

是异步的

(2)ReentrantReadWriteLock类实现写写互斥

ReentrantReadWriteLock lock=new ReentrantReadWriteLock();

 lock.WriteLock().lock();

……代码段

lock.WriteLock().unlock()

是同步的

(3)ReentrantReadWriteLock类实现读写互斥

ReentrantReadWriteLock lock=new ReentrantReadWriteLock();

方法1

 lock.readLock().lock();

……代码段

lock.readLock().unlock()

方法2

lock.WriteLock().lock();

……代码段

lock.WriteLock().unlock()

两个方法是互斥的。

 

5.单例模式与多线程

(1)立即加载/饿汉模式

立即加载是在使用类的时候对象就已经创建完毕,常见的实现办法就是new实例化。

Public class MyObject{

private static MyObject myObject=new MyObject();

private MyObject(){

}

public static MyObject getInstance(){

Return myObject

}

}

(2)延迟加载/懒汉模式

在调用getInstance()方法时实例才被创建,在方法中实例化对象。

Public class MyObject{

private static MyObject myObject;

private MyObject(){

}

public static MyObject getInstance(){

if(myObject!=null){

 

}else{

myObject=new MyObject();

}

return myObject

}

}

懒汉模式在多线程环境下容易出错,无法保持单例。

解决方案:

1.方法声明synchronized-但是效率低下

2.同步代码块—(全部方法)效率低,(关键语句)无法单例。

3.同步代码块,使用DCL双检测,多数采用这种方式。即是说在内部关键方法里再判断一次。

Public class MyObject{

Valotile private static MyObject myObject;

Public static MyObject getInstance(){

if(myObject!=null){

}else{

Thread.sleep(3000);

Synchronized(MyObject.class){

If(myObject==null){

myObject=new MyObject();

 

}

}

}

return myObject

}

}

4.static代码块实现单例模式

利用静态代码块在使用类时就已经执行的特点。

 

 

多线程编程核心技术总结(读周志明书籍的总结)