多线程知识总结

多线程

创建线程的两种方式
1.继承Thread,覆盖父类Run方法
2.实现Runable接口,重写Run方法

多线程机制并没有提高程序的运行效率,只是因为开启了多个线程,占用了服务器更多的带宽。

定时器
Timer 
TimerTask
new Timer().schedule(new TimerTask(){
    @override
    public void run(){
        
}


},多少秒后执行run,前面执行后每隔多少秒再执行一次run);

线程间的互斥与同步通信
1.方法签名上添加Synchronized
2.需要同步的代码封装到Synchronized块中
Synchronized(该同步块所在类的字节码对象){

}
经验:
要用到共同数据(包括同步锁)的若干个方法,都应该将这些方法归在同一个类中,这种设计
符合高内聚,和程序的健壮性,便于维护。
经验:
有些时候,线程会发生伪唤醒的情况,此时在同步块内使用while(){}判断,会比使用if更具有健壮性。
因为if只会判断一次,符合条件就进入。而while在循环结束后,还会判断一次。
经验:
代码编写过程中,某些运算符,本身包含逻辑的处理,如三元运算,本身就有true和false的判断,
就不需要再使用逻辑判断了。
还有if中,不需要再添加逻辑判断。

ThreadLocal实现线程范围的共享变量
变量 ThreadLocal<Integer> x = new ThreadLocal<>();
自定义类 ThreadLocal<MyObject> myObject = new ThreadLocal<>();

使用单例模式+单例类中,私有化一个静态的ThreadLocal<单例类> = new ThreadLocal<>(),
将单例对象放入ThreadLocal中,每次获取时,先判断ThreadLocal中有没有,有就取出,并返回,
没有就new一个,存入ThreadLocal,并返回。
来保证数据在该单例中被共享。

全局的ThreadLocal变量中,当多个线程使用set方法往里面存值后,就相当于往里面的map存储多条
记录,key分别是各个线程的线程名。当线程结束时,ThreadLocal会自动将死亡的线程释放。
可以调用ThreadLocal的clear方法,将线程全部清空。

多个线程访问共享对象和数据的方式
1.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runable中封装共享数据,和对数据的操作。例如
买票系统。
2.如果每个系统执行的代码不同,
    
2.1 将共享数据封装到一个对象中,然后将对象通过实现Runnable接口对象的构造方法逐一传递给各个Runable对象,每个线程对
共享数据的操作方法也放到该对象中,这样容易实现针对该数据进行的各个操作的互斥和通信。
   
 2.2 将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,
每个线程对共享数据的操作方法也分配给外部类。以便实现对共享数据进行的各个操作的互斥和通信,
作为内部类的各个Runable对象调用外部类的这些方法。
    
2.3 将共享数据封装到另一个对象中,每个线程对共享数据的操作方法也分配到那个对象中,对象作为这个外部类
中的成员变量或方法中的局部变量,每个线程的Runable对象作为外部类中的成员内部类或局部内部类。
(定义一个类,类中将共享数据定义为成员变量,并提供对该变量的操作函数,函数使用synchronized修饰,再定义多个实现了Runnable接口
口的成员内部类,该成员内部类通过内部Run方法调用同一级别的对共享数据操作的成员方法)


java5提供了线程并发库

java.util.concurrent包
automic  提供了对于基本数据类型,和类中基本数据类型的原子性操作。
AutomicInteger
java.utl.concurrent.atomic包

线程池ExecutorService threadPool = 
1.固定线程池 Executors.newFixedThreadPool(3);
2.缓存线程池 Executors.newCachedThreadPool();
3.单一线程池 Executors.newSingleThreadExecutor();(实现线程死掉后重新启动 其实就是在线程死掉后,使用原有引用变量指向一个新的线程)
关闭线程池
shutdown 所有任务执行完后,关闭所有线程
shutdownNow 当前任务完成后,关闭所有线程
线程池任务调度:给线程池中线程分配任务。可以分配多个schedule()
Executors.newScheduledThreadPool(3).schedule(Runnable,delay,unit);



Callable&Future
 Future取得的结果类型必须与Callable返回的结果类型一致,通过泛型实现。
Callable采用ExecutorService的submit()方法提交,返回的future对象可以取消任务。 

Future<T> future = threadPool.submit(new Callable<T>(){
    public String call() throws Exception{
        //Thread.sleep(2000);
        return t.type = T;
}
});
future.get();

CompletionService 用于提交一组Callable任务,其take方法返回已完成的一个Callable任务对应的Futurure
对象。类似qq种菜机制,中下一波种子,优先成熟的可以收获或偷取。

CompletionService<V> c = new ExecutorCompletionService<V>

Lock&Condition实现线程同步通信
Lock比传统线程模型中的Synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象,
两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象,锁是在代表要操作的资源的
类的内部方法中,而不是线程代码中

使用Lock注意事项
1.多个线程的lock对象必须一致.   
2.lock需要放在线程访问的共享资源中。
Lock是一个接口
实现类有ReentrantLock  
方法
    lock.lock();

    try{
        需要锁住的代码
    
    }finally{
        //执行完成后,必须释放锁,不然可能会导致线程死在锁住的代码中,后续线程无法进入。
        lock.unlock();
}

读写锁,限制代码在执行过程中是否允许同步执行读或写的操作。
对读写方法中,具体执行读写操作的代码上锁
读方法上读锁
写方法上写锁

接口ReadWriteLock 
实现类 ReentrantReadWriteLock
    lock.readLock().lock();
        try{
            需要上读锁的代码
           
    }finally{
             lock.readLock().unlock();
    }
    
    lock.writeLock().lock();
    
    try{

}finally{
    lock.writeLock.unlock();   
}

Lock可以替代Synchronize完成线程互斥
Condition可以替代Object.wait()和Object.notify()完成同步通信
Condition condition = lock.newCondition(); 
condition.await();
condition.signal();   

信号灯
Semaphore可以控制同时访问资源的线程个数。例如:实现文件的并发访问。
   
 Semaphore sp = new Semaphore(3);
acquire()获得一个许可
release()释放一个许可

Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放
“锁”,这可应用于死锁恢复的一些场合。

工具类
CyclicBarrier 彼此等待,集合后分散活动 ,分散活动后在指定地点集合,集合后再分散。
CountDownLatch 倒计时记时器 实现裁判吹口号,运动员起跑,运动员都到达终点后,开始评判成绩。
Exchanger 用于实现两个人之间的数据交换,每个人在完成一定的事务后想与对方交换数据,第一个先拿
出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据。

阻塞队列
接口BlockingQueue                                没有值时报异常   没有值时为null    没有值时阻塞,等待有值(无值)时,进行存取。
ArrayBlockingQueue    存值的方式有三种,add                   offer                 put                      put()   take()会产生阻塞
                                   取值的方式有三种 ,  remove             poll                   take   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章