一、基础概念
1.进程
内存中正在运行的一个应用程序
2.线程
进程中的一个执行流程
3.多线程
进程中有两个或两个以上这样的执行流程
4.并行
多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时
5.并发
通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的实时
6.线程同步
当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到本次访问结束以后才能对这个线程安全的方法进行访问
7.线程安全
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的
总结:
存在竞争的线程不安全,不存在竞争的线程就是安全的
二、线程的状态
线程在Running的过程中可能会遇到阻塞(Blocked)情况:
-
调用join()和sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待JVM的调度。
-
调用wait(),使该线程处于等待池(wait blocked
pool),直到notify()/notifyAll(),线程被唤醒被放到锁定池(lock blocked pool ),释放同步锁使线程回到可运行状态(Runnable) -
对Running状态的线程加同步(Synchronized)使其进入(lock blocked pool
),同步锁被释放进入可运行状态(Runnable)。
此外,在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。Thread类中的yield方法可以让一个running状态的线程转入runnable。
每个对象都有的方法(机制)
synchronized, wait, notify 是任何对象都具有的同步工具。让我们先来了解他们
monitor
他们是应用于同步问题的人工线程调度工具。讲其本质,首先就要明确monitor的概念,Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。
注意:
- wait/notify必须存在于synchronized块中。并且,这三个关键字针对的是同一个监视器(某对象的监视器)。这意味着wait之后,其他线程可以进入同步块执行。
三、线程类
1.基本线程类
基本线程类指的是Thread类,Runnable接口,Callable接口
Thread 类实现了Runnable接口,启动一个线程的方法;
Thread类相关方法:
//当前线程可转让cpu控制权,让别的就绪状态线程运行(切换)
public static Thread.yield()
//暂停一段时间
public static Thread.sleep()
//在一个线程中调用other.join(),将等待other执行完后才继续本线程。
public join()
//后两个函数皆可以被打断
public interrupte()
Callable
future模式:并发模式的一种,可以有两种形式,即无阻塞和阻塞,分别是isDone和get。其中Future对象用来存放该线程的返回值以及状态
ExecutorService e = Executors.newFixedThreadPool(3);
//submit方法有多重参数版本,及支持callable也能够支持runnable接口类型.
Future future = e.submit(new myCallable());
future.isDone() //return true,false 无阻塞
future.get() // return 返回值,阻塞直到该线程运行结束
2.高级多线程控制类
1、ThreadLocal类
2、原子类
3、Lock类
lock:在java.util.concurrent包内,共有三分实现
ReentrantLock
ReentrantReadWriteLock.ReadLock
ReentrantReadWriteLock.WriteLock
主要目的是和synchronized一样, 两者都是为了解决同步问题,处理资源争端而产生的技术。功能类似但有一些区别。
区别如下:
lock更灵活,可以自由定义多把锁的枷锁解锁顺序(synchronized要按照先加的后解顺序)
提供多种加锁方案,lock 阻塞式, trylock 无阻塞式, lockInterruptily 可打断式, 还有trylock的带超时时间版本。
本质上和监视器锁(即synchronized是一样的)
能力越大,责任越大,必须控制好加锁和解锁,否则会导致灾难。
和Condition类的结合。
四、生产消费者模式
package test;
class Qingfeng{
private int count; //包子的数量
boolean tag=false; //相当于买卖包子的平台
synchronized public void put(int count) { //生产包子的方法
if(tag) {
try {
wait(); //当有包子时,使该线程处于等待池(wait blocked pool),直到notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.count=count;
System.out.println("生产了:"+count+"个包子");
tag=true;
notify(); //唤醒卖包子方法
}
synchronized public void get(int count) { //销售包子的方法
if(tag==false) {
try {
wait(); //当没有包子时,处于等待状态
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.count=count;
System.out.println("销售了:"+count+"包子");
tag=false;
notify(); //唤醒生产包子方法
}
}
// 生产者类,进行包子的生产
class producer implements Runnable{
private Qingfeng qingfeng;
public producer(Qingfeng qingfeng) {
super();
this.qingfeng = qingfeng;
}
@Override
public void run() {
for(int i=1;i<=5;i++) {
qingfeng.put(i);
}
}
}
//销售者类,进行包子的销售
class Comsumer implements Runnable{
private Qingfeng qingfeng;
public Comsumer(Qingfeng qingfeng){
super();
this.qingfeng=qingfeng;
}
public void run() {
for(int i=1;i<=5;i++) {
qingfeng.get(i);
}
}
}
public class ProducerAndComous {
public static void main(String[] args) {
Qingfeng qingfeng=new Qingfeng();
producer p=new producer(qingfeng);
Comsumer c=new Comsumer(qingfeng);
Thread p1=new Thread(p);
Thread c1=new Thread(c);
p1.start();
c1.start();
}
}