哈哈终于开始写多线程的日志了。 先记录一下基础吧。明天写 各种生产者消费者问题的实现。
1. 任务
首先,我们平时总说线程做了什么什么,其实 Thread本身什么都不做,线程是用来驱动任务的, 你需要描述你任务的进行方式,来交给线程驱动。
定义任务的两种方式 ,实现 Runnable接口, 直接继承 Thread类。
2.线程管理。
我们不能通过优先级来控制线程的执行顺序,因为具体实现和操作系统有关。 我们通过执行器(Executor)管理 Thread对象。 常用的如ExecutorService(具有服务生命周期的Exectuor)。
3.sleep(),yield(),join();
调用sleep(),线程休眠,处于阻塞状态,此时线程处于可中断阻塞状态,调用interupt()可以中断睡眠状态,并抛出InterruptedException异常,需要注意睡眠时该线程持有的锁不释放
yield()方法表示线程已经执行完了可以让出cpu了, yield阶段如果该线程持有锁也不释放。
join()方法 比如 t1中调用 t2.join(),则表示t2执行完后 t1才可以继续执行,join()方法调用可以被中断。
4.后台线程
后台线程在所有非后台线程都结束时结束,可通过setDeamon(true);来设置, 注意设置必须在线程start前才有效
5.synchronized
所有对象对哦自动含有单一的锁,当对象上调用 synchronized方法的时候,次对象被加锁。
synchronized
修饰方法
修饰代码 ,此时由于加锁的范围减小,有利于提升性能
修饰 static ,在类层面上加锁
6 ReentrantLock
相比Synchronized
你需要尝试获取锁且最终会获取失败,尝试着获取锁一段时间,然后放弃他,synchronized 是阻塞不可中断的,ReentrantLock可以实现可中断的锁。
package com.meran.thread;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.*;
public class LockTest {
private ReentrantLock lock=new ReentrantLock();
public void untimed(){
boolean captured=lock.tryLock();
try{
System.out.println("tryLock():"+captured);
}
finally{
if(captured)
lock.unlock();
}
}
public void timed(){
boolean captured=false;
try {
captured=lock.tryLock(2, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
try{
System.out.println("tryLock(2,seconds)"+captured);
}finally{
if(captured==true){
lock.unlock();
}
}
}
public static void main(String [] args){
final LockTest test=new LockTest();
test.untimed();
test.timed();
new Thread(){
{setDaemon(true);}
public void run(){
test.lock.lock();
System.out.println("acquired");
}
}.start();
Thread.yield();
test.untimed();
test.timed();
}
}
结果并不固定,这是因为对于 Thread线程 和主线程调度的问题 我们希望看到的结果是
tryLock():true
tryLock(2,seconds)true
acquired
tryLock():false
tryLock(2,seconds)false
tryLock 并不会阻塞 ,如果不能获取锁直接返回, 带时间参数的方法设置了超时时间, 此方法可以被中断。
lock()方法阻塞在被加锁对象下,直道获取锁 ,lockInterruptibly 与lock相似但是阻塞线程可以被中断
7.原子操作,与volatile
除了 long double外 基本类型的读取和写入都是原子的,long double 会发生字撕裂 ,把long 和double生命为 volatile 可以给予其原子性 (为什么??)
多核处理器可能会缓存自己的数据,所以没有数据变更的可视性,volatile保证每次都是在内存中读取。