先明确几个概念
进程
进程是指在内存中运行的应用程序,每个进程都有自己一块独立的内存空间;一个进程中可以启用多个线程
线程
线程是进程中某一个单一的顺序执行流程.
守护线程
守护线程是线程的一种状态,它的存在是为了其它线程服务的。如JVM中的垃圾回收线程。
调用Thread类的静态方法setDaemon(true)方法将指定的线程设置为守护线程( 如:myThread.setDaemon(true) );此方法必须在线程启动前调用。
并发\并行,同步\异步,多线程
1. 并发
并发指的是,在操作系统中同一个时间段中有几个程序都是处在开始执行到执行完毕之间;并且这几个程序都在同一个处理机上运行。
2. 并行
并行是针对多处理器而言的,它体现在不同的进程是可以**同时**被执行。并行是并发的一种形态而已,并行具有并发的含义,但并发的不一定并行,也即是说并发的时间未必发生在**同一时刻**。
3. 同步
同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。
4. 异步
异步和同步是相对的,异步就是事件之间相互独立,各自运行。
5. 多线程
多线程是程序设计的一种逻辑概念,它是进程中并发运行的一段代码。
多线程,可以作为实现异步的一种手段。
举个例子:
需求:画一个正方形和一个圆形。
代码:郭靖是先画会儿正方形再画会儿圆形,最后完成需求;周伯通是一边画正方形一边画圆形,最后也完成需求。郭靖(单核cpu)是并发,周伯通(双核cpu)是并行。
线程的生命周期
线程的五种形态
- 新建状态
- 线程对象创建后,进入新建状态。
- 就绪状态
- 调用start()方法后,线程进入就绪状态。
- 进入就绪状态后,线程不会被立即执行;它只有获取了CPU分配的时间片后才会被执行。
- 运行状态
- CUP调度获取时间片的线程,此线程由就绪状态进入运行状态
- 就绪状态是线程进入运行状态的唯一入口;线程要想进入运行状态,必须先处在就绪状态等待CUP调度。
- 阻塞状态
- 发生阻塞事件后,线程进入阻塞装填
- 阻塞事件
- 等待阻塞–线程调用wait()方法
- 同步阻塞–线程未获取synchronized同步锁
- 其它阻塞–线程调用sleep()或join()或发出I/O请求;当sleep超时,join等待的线程终止或超时,I/O处理完毕后再次进入就绪状态
- 死亡状态
- 线程执行完毕或者因为异常终止,进入死亡状态
线程中的yield()
- 某个线程调用yield()方法,那么该线程由运行状态直接进入就绪状态。
- 此时,CUP会从就绪状态线程队列中选择与该线程优先级相同或者比该线程优先级高的的线程去执行(但是实际运行时,yield()的让步作用并不明显;很可能该线程会被CUP再次选中执行)。
创建线程的三种方法
继承Thread类,重写该类的run()方法
public class MyThread extends Thread { @Override public void run() { super.run(); } } class TestMyThread{ public static void main(String[] args) { Thread th = new MyThread(); th.start(); } }
实现runnable接口,重写run()方法
public class MyRunnable implements Runnable { @Override public void run() { } } class TestMyRunnable{ public static void main(String[] args) { MyRunnable mr = new MyRunnable(); Thread th = new Thread(mr); th.start(); } }
实现callable接口,重写call()方法;使用FutureTask的类来包装Callable的实现类对象,且以此FutureTask对象来作为Thread对象的target来创建线程。
public class MyCallable implements Callable<Integer>{ private int i =0; @Override public Integer call() throws Exception { int sum =0; for(;i<100;i++){ System.out.println(Thread.currentThread().getName()+" "+i); sum+=i; } return sum; } } class TestMyCallable{ public static void main(String[] args) { MyCallable mc = new MyCallable(); FutureTask<Integer> ft = new FutureTask<Integer>(mc); Thread th = new Thread(ft); th.start(); } }
一个类生产者-消费者模式示例
代码
public class ThreadTest {
public static void main(String[] args) {
Account account = new Account("123456", 0);
Thread drawMoneyThread = new DrawMoneyThread("取钱线程", account, 700);
Thread depositeMoneyThread = new DepositeMoneyThread("存钱线程", account, 700);
drawMoneyThread.start();
depositeMoneyThread.start();
}
}
class DrawMoneyThread extends Thread {
private Account account;
private double amount;
public DrawMoneyThread(String threadName, Account account, double amount) {
super(threadName);
this.account = account;
this.amount = amount;
}
public void run() {
for (int i = 0; i < 100; i++) {
account.draw(amount, i);
}
}
}
class DepositeMoneyThread extends Thread {
private Account account;
private double amount;
public DepositeMoneyThread(String threadName, Account account, double amount) {
super(threadName);
this.account = account;
this.amount = amount;
}
public void run() {
for (int i = 0; i < 100; i++) {
account.deposite(amount, i);
}
}
}
class Account {
private String accountNo;
private double balance;
// 标识账户中是否已有存款
private boolean flag = false;
public Account() {
}
public Account(String accountNo, double balance) {
this.accountNo = accountNo;
this.balance = balance;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
/**
* 存钱
*
* @param depositeAmount
*/
public synchronized void deposite(double depositeAmount, int i) {
if (flag) {
// 账户中已有人存钱进去,此时当前线程需要等待阻塞
try {
System.out.println(Thread.currentThread().getName() + " 开始要执行wait操作" + " -- i=" + i);
wait();
// 1
System.out.println(Thread.currentThread().getName() + " 执行了wait操作" + " -- i=" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
// 开始存钱
System.out.println(Thread.currentThread().getName() + " 存款:" + depositeAmount + " -- i=" + i);
setBalance(balance + depositeAmount);
flag = true;
// 唤醒其他线程
notifyAll();
// 2
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-- 存钱 -- 执行完毕" + " -- i=" + i);
}
}
/**
* 取钱
*
* @param drawAmount
*/
public synchronized void draw(double drawAmount, int i) {
if (!flag) {
// 账户中还没人存钱进去,此时当前线程需要等待阻塞
try {
System.out.println(Thread.currentThread().getName() + " 开始要执行wait操作" + " 执行了wait操作" + " -- i=" + i);
wait();
System.out.println(Thread.currentThread().getName() + " 执行了wait操作" + " 执行了wait操作" + " -- i=" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
// 开始取钱
System.out.println(Thread.currentThread().getName() + " 取钱:" + drawAmount + " -- i=" + i);
setBalance(getBalance() - drawAmount);
flag = false;
// 唤醒其他线程
notifyAll();
System.out.println(Thread.currentThread().getName() + "-- 取钱 -- 执行完毕" + " -- i=" + i); // 3
}
}
}
执行结果
取钱线程 开始要执行wait操作 执行了wait操作 -- i=0
存钱线程 存款:700.0 -- i=0
存钱线程-- 存钱 -- 执行完毕 -- i=0
存钱线程 开始要执行wait操作 -- i=1
取钱线程 执行了wait操作 执行了wait操作 -- i=0
取钱线程 取钱:700.0 -- i=1
取钱线程-- 取钱 -- 执行完毕 -- i=1
取钱线程 开始要执行wait操作 执行了wait操作 -- i=2
存钱线程 执行了wait操作 -- i=1
存钱线程 存款:700.0 -- i=2
存钱线程-- 存钱 -- 执行完毕 -- i=2
取钱线程 执行了wait操作 执行了wait操作 -- i=2
取钱线程 取钱:700.0 -- i=3
取钱线程-- 取钱 -- 执行完毕 -- i=3
取钱线程 开始要执行wait操作 执行了wait操作 -- i=4
存钱线程 存款:700.0 -- i=3
存钱线程-- 存钱 -- 执行完毕 -- i=3
存钱线程 开始要执行wait操作 -- i=4
取钱线程 执行了wait操作 执行了wait操作 -- i=4
取钱线程 取钱:700.0 -- i=5
取钱线程-- 取钱 -- 执行完毕 -- i=5
取钱线程 开始要执行wait操作 执行了wait操作 -- i=6
存钱线程 执行了wait操作 -- i=4
存钱线程 存款:700.0 -- i=5
存钱线程-- 存钱 -- 执行完毕 -- i=5
存钱线程 开始要执行wait操作 -- i=6
取钱线程 执行了wait操作 执行了wait操作 -- i=6
取钱线程 取钱:700.0 -- i=7
取钱线程-- 取钱 -- 执行完毕 -- i=7
取钱线程 开始要执行wait操作 执行了wait操作 -- i=8
存钱线程 执行了wait操作 -- i=6
存钱线程 存款:700.0 -- i=7