线程存在的意义:为了更好地利用CPU
1、程序 指令和数据的集合
2、进程 进程是在处理机上的一次执行过程 进程包含程序 进程的执行离不开程序 程序就是静态的 变成动态就成进程了
3、线程 进程中执行的一个任务 一个进程包含一个或者多个线程
4、线程的生命周期:
1)创建(new thread()创建一个线程对象)
2)就绪(调取该对象的start()方法 变成可运行 等待获取CPU的使用)
3)运行(就绪状态的线程获取CPU 执行程序代码 )
4)阻塞 (处于某种原因让出CPU 其中阻塞有三种情况:等待阻塞wait() 同步阻塞 synchronized 其他阻塞sleep()/join() 等待超时会返回就绪状态)
5)死亡(结束生命周期 三种情况:a.正常运行结束;b.线程抛异常;c.直接调用stop()方法 这个方法容易死锁)
5、线程的实现
1) 一种是 继承Thread类
在源码里面 Thread类也实现了Runnable接口
public class ThreadTest extends Thread{
private String name;
public ThreadTest(String name) {
this.name = name;
}
//重写run()方法
public void run(){
for(int i=0;i<=10;i++){
System.err.println(name+"正在运行"+i);
}
}
public static void main(String[] args) {
ThreadTest th1=new ThreadTest("A");
ThreadTest th2=new ThreadTest("B");
//调用start()方法
th1.start();
th2.start();
}
}
2)另一种是 实现Runnable接口
public abstract void run();//接口只偶一个抽象方法
public class ThreadTest implements Runnable{//这个Runnable 只有一个抽象的run()方法
private String name;
public ThreadTest(String name) {
this.name = name;
}
//重写run()方法
public void run(){
for(int i=0;i<=10;i++){
System.err.println(name+"正在运行"+i);
}
}
public static void main(String[] args) {
ThreadTest t1=new ThreadTest("A");
Thread th1=new Thread(t1);//注意这块 与集成Thread的实现不一样
ThreadTest t2=new ThreadTest("B");
Thread th2=new Thread(t2);//实现Runnable接口的类的实例当做target 作为参数传入带参数的Thread构造函数
//调用start()方法
th1.start();
th2.start();
}
}
3)Callable接口和FutureTask实现
V call() throws Exception;//有返回值 还能抛异常 并且注意 这里是call()方法 而不是run()方法 因此实现的时候重写的方法是call()
public class ThreadTest implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int s=0;
for(int i=0;i<=10;i++){
s+=i;
}
return s;
}
public static void main(String[] args) {
ThreadTest c=new ThreadTest();
//Callable需要依赖FutureTask包装器 用于接收运算结果 FutureTask是Future接口的实现类
//FutureTask实现了RunnableFuture 而RunnableFuture 继承了Runnable 和Future接口
FutureTask<Integer> f=new FutureTask<Integer>(c);
Thread t=new Thread(f);
t.start();
try {
System.err.println("阻塞 返回结果:"+f.get()+"====无阻塞 返回true/false:"+f.isDone());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
4)线程池
6、ThreadLocal
它其实是Thread的局部变量 为每个使用该变量的线程提供独立的变量副本 这个变量副本只是在该线程内使用 因此每个线程可以独立改变自己的副本 不影响其他副本
这里面可以借用数据库连接的问题先了解使用ThreadLocal的原因 不过我就不贴代码说明 网上有很多详细说明
ThreadLocal这个接口 有四个方法比较重要 (重点看源代码 这里面就不贴出来了 只是简单的总结下我看到的)
public void set(T value)//设置当前线程局部变量的值
public T get()//获得当前线程的局部变量
public void remove()//删除当前线程的局部变量
private T setInitialValue() //返回该线程局部变量的初始值 这个方法 只是作用于该ThreadLocal类的get()方法的返回值
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
Thread类中有一个ThreadLocalMap类型的变量threadLocals ThreadLocalMap是ThreadLocal的一个静态内部类
ThreadLocal.ThreadLocalMap threadLocals = null;//这个是Thread里面关于threadLocals 的源代码
threadLocals 就是这个get() set() 和setInitialValue() 的变量map 下面这个方法是get() set() 和setInitialValue()这些方法里面都具有的主要 还是防止内存溢出 这个内容又要上升一个台阶 后期再讨论
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
7、ThreadLocal和线程同步机制
都是为了解决多线程中相同变量访问冲突问题
在同步机制中 通过对象的锁机制保证同一时间只有一个线程访问 这一个线程变量被多个线程共享
8、并发 一次处理很多事 线程模型下的概念
9、并行 同时处理多事情
简单通俗来说就是 并发是 两个人用一个饮水机 并行是 两个人同时用两个饮水机