在介绍多线程之前,先介绍并发和并行的区别:
并发:是指在某一段时间内发生多个事件;
并行:是指在同一时刻发生多个事件;
在操作系统中,有多个CPU,可以并发进行多程序的并发执行,而单CPU,只能进行CPU资源的调度,并行执行程序;
进程和线程的区别:
进程:拥有自己独立的内存空间;
线程:最小的CPU调度单位
多线程实现方式:
1)继承于java.lang.Thread
- 定义类,修改run方法;
- 在其他线程过程中启动,start
2)Runnable接口实现类
注意:这里仅仅只是一个接口实现类,修改run方法,在启动线程时需要new Thread(),先创建线程对象,然后再start启动线程;
多线程带来的问题:
当多线程并发去访问同一份资源的时候,可能会引发线程安全的问题;
目前解决方案:
1)同步代码块
synchronized(监听对象)
2)同步方法
synchronize修饰
同步方法为static,则监听对象是当前对象的字节码对象object.class;
同步方法为非static,则监听对象是this
3)lock
通常使用ReentrantLock类,一种可重入的互斥锁
线程通信
常见的就是生产者和消费者案例,两者共用同一块数据资源。
1)写的过程和读的过程都要同步;
2)不能出现生产一个,消费多个的情况;
在Object类中,操作线程的方法:
都得使用当前同步监听对象来调用,否则报错IllegalMonitorStateException:
解决问题2就是需要监听共享区域是否为空,为空消费者线程就应该等待,不为空则生产者线程就得等待;也可以使用Lock和condition机制;condition.await()和condition.signal();
void wait():让当前线程失去同步监听对象,进入无限制的等待,除非其他线程唤醒它,不然永远醒不过来.
void notify() :唤醒在此同步监听对象上等待的一个线程。
void notifyAll():唤醒在此同步监听对象上等待的所有线程.
//生成者
public class Product implements Runnable{
//生成者
private ShareResource share = null;
Product(ShareResource share){
this.share = share;
}
@Override
public void run() {
for(int i=0;i<100;i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i%2 == 0){
share.push("a", "girl");
}else{
share.push("b", "boy");
}
}
}
}
//消费者
public class Consumer implements Runnable {
private ShareResource share;
Consumer(ShareResource share){
this.share = share;
}
@Override
public void run() {
for(int i =0;i<100;i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
share.popup();
}
}
}
// 共享空间
public class ShareResource {
private String name;
private String gender;
private boolean isEmpty = true; // 开始共享空间为空
synchronized public void push(String name, String gender){
while(!isEmpty){
try {
this.wait(); //等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name;
this.gender = gender;
isEmpty = false;
this.notify(); // 唤醒其他线程
}
synchronized public void popup(){
while(isEmpty){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.name + "--" + this.gender);
isEmpty = true;
this.notifyAll(); // 唤醒其他所有线程
}
}
//测试类
public class App {
public static void main(String[] args){
ShareResource shareResource = new ShareResource();
new Thread(new Product(shareResource), "Product").start();
new Thread(new Consumer(shareResource), "Consumer1").start();
new Thread(new Consumer(shareResource), "Consumer2").start();
}
}
线程类型:
join方法----联合线程
setDaemon ---- 后台线程
线程优先级:
每个线程都有优先级,优先级的高低只和线程获得执行机会的次数多少有关,并非线程优先级越高的就一定先执行,哪个线程的先运行取决于CPU的调度。