多线程基础

使用多线程的方法

继承Thread类

实现runnable接口

线程常用方法(Thread类和Object类)

这些方法要注意当前线程和该线程表述,当前线程即正在执行该代码段的线程,该线程指调用该方法的那个线程。

一般静态Thread方法调用是调用当前正在执行的线程,直接通过类名调用即可。

static Thread currentThread();
Thread.currentThread().getName()

返回当前正在执行的线程名,currentThread()是返回当前正在执行的线程。

boolean isAlive()

判断该线程是否是否处于活跃状态,即正在运行或准备运行的状态。

static void sleep(long millis)

在指定的毫秒数内让当前正在执行的线程休眠,该方法不会让线程释放锁。

long getId()

返回该线程的标识符,线程ID唯一不变,线程终止时,该线程ID可以被重新使用。

void interrupt()

中断线程,该方法不会使正在运行的线程停止,只是改变中断标志,而对于改变了中断标志的线程,调用wait,sleep,join方法时会抛出异常。如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。

该方法主要作用是让处于wait,sleep,join状态的线程退出,让线程提早结束。但会抛出异常(中断状态也会被清除),后面的语句也不再执行,如果有需要,可以在catch语句块中编写要执行的代码。

static boolean interrupted()

判断当前正在执行的线程是否处于中断状态,并清除中断状态,可以与interrupt方法一起使用使线程停止(抛出异常的方式或return)。

interrupt方法可以在其他地方通过线程引用调用设置中断,在该线程执行时即可判断是否中断并作出响应。

boolean isInterrupted()

测试线程是否已经中断,不改变中断状态。

static void yield()

暂停当前正在执行的线程对象,并执行其他线程。即让出cpu资源,并处于就绪状态等待cpu资源。

final void setPriority(int newPriority)

更改线程的优先级(1-10)。

在Java中,线程优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A是一样的。

final int getPriority()

返回线程的优先级。

final void join()

t.join()方法阻塞调用此方法的线程(calling thread),直到线程t完成,此线程再继续;通常用于在main()主线程内,等待其它线程完成再结束main()主线程。

final wait void wait()

Object方法,使线程等待,将线程加入“预执行队列”中,并释放锁,只能在同步语句块中使用。

为防止出现通知过早等问题,该方法需要在循环中使用,一般用while语句加上标识符。

final void notify()

Object方法,唤醒在此对象监视器上等待的单个线程(随机唤醒一个),被唤醒的线程加入就绪队列,等待当前线程释放锁,必须在同步语句块中使用,

final void notifyAll()

Object方法,唤醒在此对象监视器上等待的所有线程,必须在同步语句块中使用。

上述三个方法可以实现线程间通信的功能,生产者与消费者则需用到notifyAll唤醒所有等待的线程,否则会产生循环等待的问题,即生产者唤醒生产者,消费者唤醒消费者。

生产者和消费者模型

/*
简述:由生产者和消费者共同维护一个缓冲区,生产者负责向缓冲区添加消息,消费者从缓冲区消费消息,生产者和消费者线程通过缓冲区进行单向通信。
使用wait/notifyAll实现的模型,同一时间只有一个线程操作缓冲区(wait/notifyAll都要在同步块中使用),这里唤醒和等待都要基于同一个锁对象才有意义。
*/
class Person{
	private int foodNum = 0;//缓冲区
    private Object synObj = new Object();//锁对象
    Private final int MAX_NUM = 10;//缓冲区大小
    
    在wait时中断抛出异常
    public void produce() throws InterruptedException{
        synchronized(synObj){
            //这里必须用while,如果出现生产者唤醒生产者这种情况,则继续等待,下面consume同理
            while(foodNum == MAX_NUM){
                synObj.wait();
            }
            foodNum ++;//生产消息
            synObj.notifyAll();//唤醒所有线程,也必须使用该方法唤醒所有等待线程
        }
    }
    
    public void consume() throws InterruptedException{
        synchronized(synObj){
            while(foodNum == 0){
                synObj.wait();
            }
            foodNum--;//消费消息
            synObj.notifyAll();
        }
    }	
}

class Producer implements Runnable{
	Person person ;
    
    public Producer(Person person){
        this.person = person;
    }
    
    public void run(){
        while(true){//根据具体业务而定
            //发生中断时会抛出异常,提前结束等待(调用interrupt方法,中断当前线程),所以需要     		   
            //在出现这种情况时进行相应的处理,有时候业务需要提前结束等待。
            try{
            	person.produce();
        	}catch(InterruptedException e){
            	e.printStackTrace();
       		}
        }
    }
}

class Consumer implements Runnable{
    Person person;
    
    public Consumer(Person person){
        this.person = person;
    }
    
    public void run(){
        while(true){
            try{
            	person.consume();
        	}catch(InterruptedException e){
            	e.printStackTrace();
       		}
        }
    }
}

通过管道进行线程间通信

PipedInputStream(从输入流中读取数据) PipedOutputStream //字节流
PipedReader PipedWriter //字符流
//四个类都有connect方法,用于相互连接,一个线程通过PipedOutputStream或PipedWriter向流输入数据,另一个线程取数据
//管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。

Lock的使用(显式锁)

ReentrantLock
/*
ReentrantLock:一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。 
*/
//典型代码
public class Demo{
    private final Lock lock = new ReentrantLock();
    public void test(){
        lock.lock();
        //lock获取锁后运行代码,当抛出异常时不像synchronized一样,自动释放锁,所以需要try语句保证最后能释放锁,不然会有死锁的可能。
        try{
            //do something ...
        }finally{
            lock.unlock();
        }
    }
}

与Lock关联的Condition

理解:conditon通过lock.newCondition()创建,实现了粒度更细的等待/通知模型。一个Lock对象可以创建多个Condition,而一个Condition可以和多个线程关联,实现了范围性的等待/通知。

线程执行到condition.await()时等待并释放锁,另一个线程通过condition.signal()/condition.signalAll()唤醒同一个condition内等待的线程。一个condition即为一个条件队列,通过调用不同的condition即可唤醒不同的条件队列等待的线程。

public class demo{
	private final Lock lock = new ReetrantLock();
    private Condition conditon1 = lock.newConditon();
    private Condition condition2 = lock.newConditon();
    
    public void await1(){
        lock.lock();
        try{
            do something ...
            condition1.await();
            do something ...
        }catch(InterruptedException e){
            e.prinStackTrace();
        }finally{
            lock.unlock();
        }
    }
    
    public void await2(){
        lock.lock();
        try{
            do something ...
            condition12.await();
            do something ...
        }catch(InterruptedException e){
            e.prinStackTrace();
        }finally{
            lock.unlock();
        }
    }
    
    public void signal1(){
        lock.lock();
        try{
            do something ...
            condition11.signalAll();
            do something ...
        }finally{
            lock.unlock();
        }
    }
    
     public void signal2(){
        lock.lock();
        try{
            do something ...
            condition12.signalAll();
            do something ...
        }finally{
            lock.unlock();
        }
    }
}
公平锁和非公平锁

锁Lock分为“公平锁”和“非公平锁”,公平锁表示线程获取锁的顺序是按照FIFO先进先出的顺序,非公平锁则是一种获取锁的抢占机制,随机获取锁。

lock = new ReentrantLock(true)//设为公平锁,默认为false
有条件的执行线程
 boolean tryLock()

仅在调用时锁未被另一个线程保持的情况下,才获取该锁。 如果锁被另一个线程保持,则此方法将立即返回 false 值。 与lock()不同的是,他不会等待获取锁,而是直接返回false。

boolean tryLock(long timeout,TimeUnit unit) throws InterruptedException

如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。

因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取,或者报告所用的等待时间。

理解:lock锁可实现有条件,有时间限制的获取锁,在中断情况下放弃执行后面的同步代码块,并抛出异常,在实现时可通过设置中断有条件的让一个线程是否执行同步代码。

Conditon部分方法
void awaitUninterruptibly()	

造成当前线程在接到信号之前一直处于等待状态。被中断后不抛出异常,继续执行。

这里注意,await()方法在中断时会抛出异常,而此方法中断相当于唤醒当前线程的信号,即在中断,signal(),signalAll()唤醒当前线程前一直处于等待状态。

boolean awaitUntil(Date deadline) throws InterruptedException

造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。 中断后抛出异常。

ReentrantReadWriteLock

读写锁,与ReentrantLock不同的是,读写锁表示有两个锁,一个是读操作相关的锁,另一个是写相关操作的锁。多个读锁之间不互斥,读锁与写锁互斥,写锁和写锁互斥

在某些不需要操作实例变量的方法中,可以使用读锁提高运行速度。

lock.readLock().lock();//获得读锁
lock.readLock().unlock();//释放读锁
lock.writeLock.lock();//获得写锁
lock.writeLock().unlock();//释放读锁
posted @   带着键盘流浪  阅读(111)  评论(0)    收藏  举报
点击右上角即可分享
微信分享提示