这里写目录标题
1.进程:
I. 运行时的程序,称为进程。
II. 单核CPU在任一时间点上,只能运行一个进程。
III. 宏观并行、微观串行
IV. cpu get NumberOfCores 获得核心数
2.线程:
I. 轻量级进程
II. 程序中的一个顺序控制流程,也是CPU的基本调度单位。
III. 进程可以由单个或多个线程组成,彼此间完成不同的工作,交替执行,称为多线程
IV. JVM虚拟机是一个进程,默认包含主线程(Main函数),可以通过代码创建多个独立线程,与Main线程并发执行。
3.线程的组成:
I.CPU时间片
II. 运行数据:
(1).堆空间:存储线程需要使用的对象,多个线程可以共享堆中的对象
(2).栈空间:存储线程需要使用的局部变量,每个线程都拥有独立的栈
4. 线程的创建:
I. 继承Thread类,自定义类变成线程类
II. 实现Runnable接口,赋予自定义类线程任务的能力。
III. 实现Runnable接口,不影响类继承,更灵活。
IV. 线程创建后,需要调用start();方法,来启动线程,由JVM调用run()方法。直接调用run()方法并不是线程的启动。
MyThread t1 = new MyThread();
t1.start();
MyRunnable mr = new MyRunnable();
Thread t2 = new Thread(mr);
t2.start();
class MyThread extends Thread{
public void run() {
for(int i = 1;i<=50;i++) {
System.out.println(Thread.currentThread().getName()+"-"+i);
}
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 1;i<=50;i++) {
System.out.println("MyRunnable -"+i);
}
}
}
5.线程的状态:
6. 线程常见方法:
I. 休眠 sleep(long millis);
(1).当前线程主动休眠 millis毫秒,进入有限期等待!
II. 放弃 yield();
(1).当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片
III. 结合 join();
(1).允许其他线程加入到当前线程中,当前线程进入无限期等待!
//t1.join() 等待t1执行完后,才能重新恢复就绪状态
8. 线程安全的问题:
I. 当多线程并发访问临界资源时,如果破坏了原子操作,可能会导致数据不一致。
II. 临界资源:共享资源(同一对象、堆空间),一次仅允许一个线程使用,才可保证其正确性
III.原子操作:不可分割的多步操作,被视作为一个整体,其顺序和步骤不能打乱或缺省。
9. synchronized 同步锁:
I.每个对象都有一个互斥锁标记,用来分配给线程。
II.只有持有对象互斥锁标记的线程,才能进入对该对象加锁的同步操作中(同步方法、同步代码块)。
III.只有线程退出同步操作时,才会释放相应的锁标记
10. 同步方式:
10、同步方式
I.同步代码块
(1). synchronized(临界资源对象){
//原子操作
}
II. 同步方法
(1) . synchronized 返回值类型 方法名成(参数列表){
//原子操作
}
11.线程的状态:
12. 同步规则:
I. 只有在调用包含同步代码块的方法或者是同步方法时,才需要对象的锁标记
II. 如果调用的是不包含同步代码块的方法或普通方法时,则不需要锁标记,直接调用即可。
III. 已知线程安全的内容:StringBuffer、Vector、Hashtable(定义的方法加了synchronize)
13. 死锁、生产者与消费者:
public class TestCustomer {
public static void main(String[] args) {
Shop shop = new Shop();
Thread p = new Thread(new Product(shop),"生产者");
Thread c = new Thread(new Customer(shop),"消费者");
p.start();
c.start();
}
}
//商品
class Goods{
private int id;
public Goods(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
//商店
class Shop{
Goods goods;
boolean flag;
//生产者调用的方法
public synchronized void saveGoods(Goods goods) throws InterruptedException {
//1.判断商品是否充足
if(flag == true) { //商品充足
this.wait(); //商品充足,进入等待状态
}
System.out.println(Thread.currentThread().getName()+"生产并在商场里存放了"+goods.getId()+"件商品");
this.goods = goods;
flag = true;
this.notifyAll();
}
//消费者调用的方法
public synchronized void buyGoods() throws InterruptedException {
if(flag == false) {
this.wait(); //消费者进入等待队列
}
System.out.println(Thread.currentThread().getName()+"购买了"+goods.getId()+"件商品");
this.goods = null;
flag = false;
this.notifyAll();
}
}
//生产者
class Product implements Runnable{
Shop shop;
public Product(Shop shop) {
this.shop = shop;
}
@Override
public void run() {
for(int i = 1;i<20;i++) {
try {
shop.saveGoods(new Goods(i));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class Customer implements Runnable{
Shop shop;
public Customer(Shop shop) {
this.shop = shop;
}
@Override
public void run() {
for(int i = 1;i<20;i++) {
try {
shop.buyGoods();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
14. 线程通信:
I. 等待
(1) wait();
(2) 必须在对obj(对象)加锁的同步代码块(或同步方法)中,在一个线程执行期间,调用了obj.wait(),该线程会释放所拥有的锁标记。同时,进入到obj的等待队列中。等待唤醒
II. 通知(唤醒)
(1).notify();、notifyAll();
(2).必须在对obj加锁的同步代码块(或同步方法)中,从obj的Waiting(等待队列)中随机释放一个或全部线程。对自身线程无影响。