并发、并行
进程
- 正在运行的程序(软件)就是一个独立的进程
- 线程是属于进程的,一个进程中可以同时运行很多个线程
- 进程中的多个线程其实是并发和并行执行的
并发
进程中的线程是由CPU负责调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能往前执行,CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发
eg:老师以很快的速度给班上的每个学生分别发糖
并行
在同一个时刻上,同时有多个线程在被CPU调度执行
多线程到底是怎么在执行的:并发和并行同时进行的
线程的生命周期
也就是线程从生到死的过程中,经历的各种状态及状态转换
Java线程的状态
Java总共定义了6种状态
6种状态都定义在Thread类的内部枚举类中
6种状态的相互转变
sleep不会释放锁,而wait会
乐观锁、悲观锁
悲观锁:
一上来就加锁,没有安全感。每次只能一个线程进入访问完毕后,再解锁。线程安全,性能较差
乐观锁:
一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制。线程安全,性能较好
需求:1变量,100个线程,每个线程对其加100次
public class Test1 {public static void main(String[] args) {//需求:1变量,100个线程,每个线程对其加100次//任务只有一个,所以new一个就行Runnable target = new MyRunnable();//用于完成这个任务的线程有100个for (int i = 1; i <= 100; i++) {new Thread(target).start();}}
}
public class MyRunnable implements Runnable{private int count; //记录浏览人数@Overridepublic void run() {//每个线程+100次for (int i = 0; i < 100; i++) {System.out.println("count=====>"+(++count));}}
}
运行结果:
按理说应该是加到了10000,但是最终只加到了9999→出现了线程安全问题(多个线程访问同一个共享资源)
有时候也能加到10000,即有时候安全有时候不安全
比如两个线程都将10拽出去然后加1再放回去,导致了少加了一次
解决方法1:
悲观锁
对代码加锁使每次对count进行修改时加锁,而不是对方法加锁使某一个线程加满100次之后再让下一个线程进行加
public class MyRunnable implements Runnable{private int count; //记录浏览人数@Overridepublic void run() {//每个线程+100次for (int i = 0; i < 100; i++) {//Runnable对象只new了1份,故this就是代指本次任务对象即target对象System.out.println(this); //保险起见打印一下看看this是不是Runnable对象synchronized (this) {System.out.println("count=====>"+(++count));}}}
}
运行结果
与之前不同的是,现在count是一个一个加的,即打印出的count是有序的,且能加到10000了,线程安全了
解决方法2:
乐观锁
虽然代码出现了线程安全问题,但是最终的结果也是很接近我们想要的结果的,即只是偶尔发生了线程冲突
比较和交换算法CAS
整数修改的乐观锁
原子类实现
public class Test2 {public static void main(String[] args) {//需求:1变量,100个线程,每个线程对其加100次//任务只有一个,所以new一个就行Runnable target = new MyRunnable2();//用于完成这个任务的线程有100个for (int i = 1; i <= 100; i++) {new Thread(target).start();}}
}
public class MyRunnable2 implements Runnable{
// private int count; //记录浏览人数// 整数修改的乐观锁:原子类实现的private AtomicInteger count = new AtomicInteger();@Overridepublic void run() {//每个线程+100次for (int i = 0; i < 100; i++) {//count.incrementAndGet()效果等价于++countSystem.out.println(Thread.currentThread().getName() + "count=====>" + count.incrementAndGet());}}
}