线程和进程
进程:一个程序
一个进程往往可以包含多个线程,至少包含一个
线程:
对于java而言:Thread,Runnable,Callable
java不可以开启线程
并发(多个线程操作同一个资源)
CPU一核
并行(多人一起行走)
CPU多核,多个线程可以同是执行,线程池
//获取CPU的核数
System.out.println(Runtime.getRuntime().availableProcessors());
并发编程的本质:充分利用CPU的资源
线程的六个状态
//新生
NEW
//运行
RUNNABLE
//阻塞
BLOCKED
//等待,死死地等
WAITING
//超时等待
TIMED WAITING
//终止
TERMINATEO
wite/sleep的区别
1、来自不同的类
wait——Object
sleep——Thread
2、关于锁的释放
wite会释放,sleep不会释放
3、使用的范围不同
wite:必须同步在代码块中
sleep:可以在任何地方用
4、是否捕获异常
wite不需要捕获异常
sleep必须捕获异常
lock锁
-
- 传统:synchronized
//线程是一个单独的资源类,没有任何附属的操作
public class saleTicket {
public static void main(String[] args){
//并发、多线程操作同一个资源类,把资源类丢进线程里
Ticket ticket=new Ticket();
Ticket ticket2=new Ticket();
//@FunctionalInterface 函数式接口
//lambda表达式 (参数)->{代码}
new Thread(()->{
for(int i=1;i<50;i++){
ticket.sale();}
},"A").start();
new Thread(()->{
for(int i=0;i<50;i++){
ticket.sale();}
},"B").start();
new Thread(()->{
for(int i=0;i<50;i++){
ticket.sale();}
},"C").start();
}
}
class Ticket{
//属性、方法
private int number=50;
//synchronized 本质:队列,排队
public synchronized void sale(){
if(number>0){
System.out.println(Thread.currentThread().getName()+
"卖出了"+(number--)+"票,剩余:"+number+"张");
}
}
}
-
- Lock接口
公平锁:十分公平,先来后到
非公平锁:不公平,可以插队(默认)
//lock三部曲
//1、new ReentrantLock();
//2、lock.lock();//加锁
//3、finally=>lock.unlock();//解锁
class Ticket2{
int number=30;
Lock lock= new ReentrantLock();
public void sale(){
lock.lock();//加锁
try{
if(number>0){
System.out.println(Thread.currentThread().getName()+
"卖出了"+(number--)+"票,剩余:"+number+"张");
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();//解锁
}
}
}
Synchornized和look的区别
-
-
- Synchornized是内置的关键字,look是一个java类
- Synchornized无法判断获取锁的状态,lock可以判断是否获取了锁
- Synchornized会自动释放锁,lock必须手动释放锁,否则死锁
- Synchornized线程一(获得锁,阻塞),线程二(等待)lock就不一定等待下去
- Synchornized是可重入锁,不可以中断,非公平。Lock可重入锁,可以判断,非公平(可以自己设置)
- Synchornized审核锁少量的代码同步问题,Lock适合锁大量的同步代码
-
生产者和消费者问题
Synchornized版
public class PC {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.decrement();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.increment();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.decrement();
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.increment();
}
},"D").start();
}
}
class Data {
private int number = 0;
public synchronized void increment() {
if (number > 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
this.notifyAll();
}
public synchronized void decrement() {
if (number <= 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
this.notifyAll();
}
}
当线程大于两个时便可能存在虚假唤醒的情况:因为使用的是if,执行完if内的内容唤醒后便会继续执行后续代码而不会再次判断等待条件, 换句话说,等待应该总是出现在循环中的
public class PC {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.decrement();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.increment();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.decrement();
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.increment();
}
},"D").start();
}
}
class Data {
private int number = 0;
public synchronized void increment() {
while (number > 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
this.notifyAll();
}
public synchronized void decrement() {
while (number <= 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
this.notifyAll();
}
}
Lock版
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PC {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.decrement();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.increment();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.decrement();
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.increment();
}
},"D").start();
}
}
class Data {
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() {
lock.lock();
try {
while (number > 0) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
condition.signalAll();
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
while (number <= 0) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
condition.signalAll();
} finally {
lock.unlock();
}
}
}
condition实现精准通知唤醒
public class Demo05 {
public static void main(String[] args) {
Data01 data01 = new Data01();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data01.A();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data01.B();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data01.C();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
}
}
// 判断等待,业务,通知
//A执行完调用B,B执行完调用C,C执行完调用A
class Data01 {
private int num = 1;// 1A 2B 3C
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void A() throws InterruptedException {
lock.lock();
try {
// 业务代码,判断=>执行=>通知!
while (num!=1){
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAAAA");
num = 2;
// 唤醒指定的线程,B
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void B() throws InterruptedException {
lock.lock();
try {
while (num!=2){
condition2.await();
}
num = 3;
System.out.println(Thread.currentThread().getName()+"=>BBBBB");
// 唤醒指定的线程,C
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void C() throws InterruptedException {
lock.lock();
try {
while (num!=3){
condition3.await();
}
num = 1;
System.out.println(Thread.currentThread().getName()+"=>CCCCC");
// 唤醒指定的线程,A
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
8锁现象
synchronized 锁的对象是方法的调用者
static方法类一加载就有了,锁的是class模板
例1、
package com.haust.lock8;
import java.util.concurrent.TimeUnit;
/**
* 8锁,就是关于锁的8个问题
* 1、标准情况下,两个线程先打印 发短信还是 先打印 打电话? 1/发短信 2/打电话
* 1、sendSms延迟4秒,两个线程先打印 发短信还是 打电话? 1/发短信 2/打电话
*/.
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
// 锁的存在
new Thread(()->{
phone.sendSms();
},"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
// synchronized 锁的对象是方法的调用者!、
// 两个方法用的是同一个对象调用(同一个锁),谁先拿到锁谁执行!
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);// 抱着锁睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
// 先执行 发短信,后执行打电话
例2、
package com.haust.lock8;
import java.util.concurrent.TimeUnit;
/**
* 3、 增加了一个普通方法后!先执行发短信还是Hello?// 普通方法
* 4、 两个对象,两个同步方法, 发短信还是 打电话? // 打电话
*/
public class Test2 {
public static void main(String[] args) {
// 两个对象,两个调用者,两把锁!
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
new Thread(()->{
phone2.hello();
},"C").start();
}
}
class Phone2{
// synchronized 锁的对象是方法的调用者!
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
// 这里没有锁!不是同步方法,不受锁的影响
public void hello(){
System.out.println("hello");
}
}
// 先执行打电话,接着执行hello,最后执行发短信
例3、
package com.haust.lock8;
import java.util.concurrent.TimeUnit;
/**
* 5、增加两个静态的同步方法,只有一个对象,先打印 发短信?打电话?
* 6、两个对象!增加两个静态的同步方法, 先打印 发短信?打电话?
*/
public class Test3 {
public static void main(String[] args) {
// 两个对象的Class类模板只有一个,static,锁的是Class
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
// Phone3唯一的一个 Class 对象
class Phone3{
// synchronized 锁的对象是方法的调用者!
// static 静态方法
// 类一加载就有了!锁的是Class
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
// 先执行发短信,后执行打电话
例4、
package com.haust.lock8;
import java.util.concurrent.TimeUnit;
/**
* 7、1个静态的同步方法,1个普通的同步方法 ,一个对象,先打印 发短信?打电话?
* 8、1个静态的同步方法,1个普通的同步方法 ,两个对象,先打印 发短信?打电话?
*/
public class Test4 {
public static void main(String[] args) {
// 两个对象的Class类模板只有一个,static,锁的是Class
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
// Phone3唯一的一个 Class 对象
class Phone4{
// 静态的同步方法 锁的是 Class 类模板
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
// 普通的同步方法 锁的调用者(对象),二者锁的对象不同,所以不需要等待
public synchronized void call(){
System.out.println("打电话");
}
}
// 7/8 两种情况下,都是先执行打电话,后执行发短信,因为二者锁的对象不同,
// 静态同步方法锁的是Class类模板,普通同步方法锁的是实例化的对象,
// 所以不用等待前者解锁后 后者才能执行,而是两者并行执行,因为发短信休眠4s
// 所以打电话先执行。
小结
- new this 具体的一个手机
- static Class 唯一的一个模板