一、概念
并发 | 并发的实质是一个或多个物理CPU,在若干个程序之间多路复用,并发性是对有限物理资源强制行使,多用户共享以提高效率【例如:两个或多个事件在同一时间段内发生:边打游戏边看电视】 |
并行 | 同时发生两个并发事件【例如:同一时刻发生,你和朋友一起打游戏】 |
进程 | 一个在内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程可以有多个线程【例如:QQ.exe】 |
线程 | 进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据 |
所以系统中会存在:多线程并发【多个任务 同一时间段争CPU】;此外:java本身就是多线程的
二、实现
1、继承Thread类
public class TestDemo {
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();
// start 与 run 区别
threadDemo.start(); // 实现多线程运行,无需等待run方法体执行完毕,可以直接向下执行
threadDemo.run(); // 串行运行,Run 方法运行结束,此线程终止,才可以继续向下执行
}
}
// 继承Thread类 但是存在:java单继承 不易扩展的问题
class ThreadDemo extends Thread{
@Override
public void run() {
System.out.println("ThreadDemo方法逻辑");
}
}
2、实现Runnable接口
public class TestDemo {
public static void main(String[] args) {
RunnableDemo runnableDemo = new RunnableDemo();
// 多个线程同时执行runnableDemo,可以共享index变量,继承Thread类需要将变量置为static
Thread t1 = new Thread(runnableDemo,"线程1");
Thread t2 = new Thread(runnableDemo,"线程2");
Thread t3 = new Thread(runnableDemo,"线程3");
t1.start();t2.start();t3.start();
}
}
// 优点:适合资源共享;避免单继承的局限性;
class RunnableDemo implements Runnable{
private Integer index = 3;
@Override
public void run() {
// Runnable的run()方法不能抛出异常,必须在run()捕获;
try{
System.out.println(Thread.currentThread().getName()+": RunnableDemo方法逻辑"+index--);
}catch (Exception e){
}
}
}
//线程3: RunnableDemo方法逻辑3
//线程1: RunnableDemo方法逻辑2
//线程2: RunnableDemo方法逻辑1
3、实现Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class TestDemo {
public static void main(String[] args) throws Exception {
CallableDemo callableDemo = new CallableDemo();
// 执行Callable 任务后,可以获取一个 Future 的对象,
FutureTask<Integer> future = new FutureTask<Integer>(callableDemo);
new Thread(future).start();
// 在 Future 对象上调用 get 就可以获取到 Callable 任务返回的 数据 了
System.out.println(future.get());
}
}
// 实现Callable接口,重写call()方法来实现一个线程;
class CallableDemo implements Callable<Integer> {
private int index = 10;
// Callable可以在任务结束后提供一个返回值;
@Override
// Callable接口中的call()方法可以抛出异常;
public Integer call() throws Exception {
return getSum(index);
}
public Integer getSum(int x){
if (x==0){
return 0;
}
return x+getSum(--x);
}
}
// 55
三、常用方法
方法名 | 说明 |
setPriority(int newPriority) | 设置线程的优先级别,范围:1-10,默认为5,优先级越高,表示获取CPU机会越多 |
sleep(long millis) | 可以指定毫秒数,使线程休眠,休眠结束后可以继续执行线程 |
yield() | 暂停当前正在执行的线程对象(以及放弃当前拥有的cpu资源),并执行其他线程;就绪后仍然可以抢占资源 |
join() | 作用是:“等待该线程终止",join()后面的方法要等该线程执行完才会执行。 |
setDaemon(boolean on) | 主线程的附庸,主线程执行完毕后不管守护线程有没有执行完,都会停止。 |
wait() | 释放锁,进入阻塞,需要notify()或者notifyAll()唤醒 |
wait(long timeout) | 在超过指定的时间前,释放锁,进入等待队列 |
notify() | 随机唤醒,通知一个线程,对应wait() |
notifyAll() | 唤醒、通知所有wait()的线程 |
四、生命周期
生命周期 | 描述 |
新建状态(NEW) | 线程对象创建后,即进入了新建状态 :Thread t = new MyThread(); |
就绪状态(RUNNABLE) | 调用线程对象的start()方法,线程进入有序状态 |
运行状态(RUNNING) | 进入就绪状态后,CPU开始调度执行方法 |
阻塞状态(BLOCKED) | 等待阻塞:wait();同步阻塞:synchronized;其他阻塞:sleep()、join()、I/O请求 |
线程死亡(DEAD) | 执行完成或异常退出 |
五、线程安全
1、同步代码块
// 存在线程安全
public class TestDemo {
public static void main(String[] args) throws Exception {
RunnableDemo runnableDemo = new RunnableDemo();
Thread t1 = new Thread(runnableDemo,"线程1");
Thread t2 = new Thread(runnableDemo,"线程2");
t1.start();
t2.start();
}
}
class RunnableDemo implements Runnable{
private Integer index = 1;
@Override
public void run() {
try {
// 存在两个线程拿到index为1,同时进入判断,然后执行index--;
if (index>0){
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+": RunnableDemo方法逻辑"+index--);
}
} catch (InterruptedException e) {
}
}
}
// 其中一直情况:
//线程1: RunnableDemo方法逻辑1
//线程1: RunnableDemo方法逻辑1
//加同步代码块后
public class TestDemo {
public static void main(String[] args) throws Exception {
RunnableDemo runnableDemo = new RunnableDemo();
Thread t1 = new Thread(runnableDemo,"线程1");
Thread t2 = new Thread(runnableDemo,"线程2");
t1.start();
t2.start();
}
}
class RunnableDemo implements Runnable{
private Integer index = 1;
@Override
public void run() {
try {
// 将同步锁加入到代码块上,括号里面上锁的对象(this)只要唯一即可
synchronized (this){
if (index>0){
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+": RunnableDemo方法逻辑"+index--);
}
}
} catch (InterruptedException e) {
}
}
}
//线程1: RunnableDemo方法逻辑1
2、同步方法
public class TestDemo {
public static void main(String[] args) throws Exception {
RunnableDemo runnableDemo = new RunnableDemo();
Thread t1 = new Thread(runnableDemo,"线程1");
Thread t2 = new Thread(runnableDemo,"线程2");
t1.start();
t2.start();
}
}
class RunnableDemo implements Runnable{
private Integer index = 1;
@Override
public void run() {
try {
sun();
} catch (Exception e) {
}
}
// 将同步锁加入到方法上面
public synchronized void sun() throws Exception {
if (index>0){
Thread.sleep(200);
System.out.println(Thread.currentThread().getName()+": RunnableDemo方法逻辑"+index--);
}
}
}
3、锁机制Lock
lock() | 获取锁,如果锁被占用,则等待 |
tryLock() | 尝试获取锁,成功:true,失败:false,不阻塞 |
unlock | 释放锁 |
public class TestDemo {
public static void main(String[] args) throws Exception {
RunnableDemo runnableDemo = new RunnableDemo();
Thread t1 = new Thread(runnableDemo,"线程1");
Thread t2 = new Thread(runnableDemo,"线程2");
t1.start();
t2.start();
}
}
class RunnableDemo implements Runnable{
private Integer index = 1;
// ReentrantLock可重入锁,synchronized也是重入锁的一种
private Lock rLock = new ReentrantLock();
@Override
public void run() {
rLock.lock();
// 重复上锁,即重入锁
rLock.lock();
try {
sun();
} catch (Exception e) {
}finally {
// 阿巴 阿巴 阿巴
rLock.unlock();
rLock.unlock();
}
}
public void sun() throws Exception {
if (index>0){
Thread.sleep(200);
System.out.println(Thread.currentThread().getName()+": RunnableDemo方法逻辑"+index--);
}
}
}
六、线程池
newFixedThreadPool | 创建一个固定长度的线程池,当达到线程最大数量时,线程池的规模将不再变化 |
newCachedThreadPool | 创建一个可缓存的线程池,如果当前线程池的规模超出处理需求,将回收空的线程;当需求增加时,会增加线程数量;线程池规模无限制。 |
newSingleThreadExecutor | 创建一个单线程的Executor,确保任务对了,串行执行 |
newScheduledThreadPool | 创建一个固定长度的线程池,而且以延迟或者定时的方式来执行 |
public class TestDemo {
public static void main(String[] args) throws Exception {
Object o = new Object();
RunnableDemo runDemo1 = new RunnableDemo();
RunnableDemo runDemo2 = new RunnableDemo();
RunnableDemo runDemo3 = new RunnableDemo();
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(2);
System.out.println("----------------------newFixedThreadPool----------------------");
Thread.sleep(1000);
newFixedThreadPool.submit(runDemo1);
newFixedThreadPool.submit(runDemo2);
newFixedThreadPool.submit(runDemo3);
Thread.sleep(1000);
System.out.println("--------------------------------------------------------------");
Thread.sleep(1000);
System.out.println("----------------------newCachedThreadPool----------------------");
newCachedThreadPool.submit(runDemo1);
newCachedThreadPool.submit(runDemo2);
newCachedThreadPool.submit(runDemo3);
Thread.sleep(1000);
System.out.println("--------------------------------------------------------------");
System.out.println("----------------------newSingleThreadExecutor----------------------");
Thread.sleep(1000);
newSingleThreadExecutor.submit(runDemo1);
newSingleThreadExecutor.submit(runDemo2);
newSingleThreadExecutor.submit(runDemo3);
Thread.sleep(1000);
System.out.println("--------------------------------------------------------------");
System.out.println("----------------------newScheduledThreadPool----------------------");
Thread.sleep(1000);
newScheduledThreadPool.schedule(runDemo1,10,TimeUnit.SECONDS);
newScheduledThreadPool.schedule(runDemo2,10,TimeUnit.SECONDS);
newScheduledThreadPool.schedule(runDemo3,10,TimeUnit.SECONDS);
}
}
class RunnableDemo implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+": 方法逻辑");
}
}
//----------------------newFixedThreadPool----------------------
//pool-1-thread-1: 方法逻辑
//pool-1-thread-2: 方法逻辑
//pool-1-thread-1: 方法逻辑
//--------------------------------------------------------------
//----------------------newCachedThreadPool----------------------
//pool-2-thread-1: 方法逻辑
//pool-2-thread-3: 方法逻辑
//pool-2-thread-2: 方法逻辑
//--------------------------------------------------------------
//----------------------newSingleThreadExecutor----------------------
//pool-3-thread-1: 方法逻辑
//pool-3-thread-1: 方法逻辑
//pool-3-thread-1: 方法逻辑
//--------------------------------------------------------------
//----------------------newScheduledThreadPool----------------------
//pool-4-thread-1: 方法逻辑
//pool-4-thread-2: 方法逻辑
//pool-4-thread-1: 方法逻辑