1.并发和并行
并行:在同一时刻,有多个指令在多个CPU上同时执行
并发:在同一时刻,有多个指令在单个CPU上交替执行
2.进程和线程
进程:就是操作系统中正在运行的一个应用程序
线程:就是应用程序中做的事情。比如:360软件中的杀毒,扫描木马,清理垃圾
3.Java多线程的实现方案
1.继承Thread类
//继承(extends)Thread类并重写main方法
public class MyThread extends Thread {
@Override
public void run() {
for (int a = 0; a < 100; a++) {
System.out.println("线程开启了" + a);
}
}
}
//在main方法中调用start()方法
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start();
t2.start();
2.实现Runnable接口
//定义自定义类并实现(implements)Runable接口
public class MyRunable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程开启了" + i);
}
}
}
//创建Thread对象和自己定义的对象 将Runnable传递给Thread对象 并通过调用 start() 方法来启动线程
public static void main(String[] args) {
MyRunable myRunable = new MyRunable();
Thread t1 = new Thread(myRunable);
Thread t2 = new Thread(myRunable);
t1.start();
t2.start();
}
3.使用 Callable 和 Future
必须要在线程启动后调用get方法 否则会堵塞
//定义一个类实现Callable方法
public class MyCallable implements Callable<String> {
//在MyCallable类中重写call()方法
@Override
public String call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println("向女生表白" + i);
}
return "答应";
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建MyCallable对象
MyCallable myCallabl= new MyCallable();
//创建FutureTask对象 并把MyCallable对象作为参数传递进去
FutureTask<String> futureTask = new FutureTask<>(myCallabl);
//创建线程对象 并把FutureTask对象作为参数传递进去
Thread thread = new Thread(futureTask);
thread.start();
//get()方法可以获取MyCallable方法结束后输出的结果
System.out.println(futureTask.get());
}
三种方式的对比
/ | 优点 | 缺点 |
---|---|---|
实现Runable,Callable接口 | 扩展性强,实现该接口的同时还可以继承其他的类 | 编程相对复杂,不能直接使用Thread类中的方法 |
继承Thread类 | 编程比较简单,可以直接使用Thread类中的方法 | 可扩展性较差,不能再继承其他的类 |
Thread方法设置/获取名字
获取线程对象的name:
//前情提要:Mythread继承了Thread
Mythread mythread = new Mythread();
Mythread mythread1 = new Mythread();
String tname = mythread.getName();
System.out.println(tname);
设置线程对象的name:
方法1:void setName(String name)
mythread.setName("黄乘明爱吃屎");
方法2:通过构造方法设置名字(因为Thread类本来就自带了name成员变量)
//只需要调用父类的构造方法即可
public Mythread(String name) {
super(name);
}
获得线程对象
获得当前正在运行的线程对象
String tname = Thread.currentThread().getName();//static方法
sleep方法:睡多少毫秒
Thread.sleep(1000);//static方法
线程的优先级
设置优先级
public final void setPriority(int newPriority)
获得优先级
public int getPriority()
守护线程/后台线程
守护线程(Daemon Thread)是一种特殊类型的线程,用于执行后台任务或辅助性工作,当所有的用户线程(非守护线程)都结束时,JVM(Java虚拟机)会终止所有的守护线程,且不等待它们完成
Thread thread = new Thread()
thread.setDaemon(true); // 将线程设置为守护线程
同步代码块
public class ticket implements Runnable{
private int count = 100;
Object lock = new Object();
@Override
public void run() {
while (true){
synchronized (lock){
if (count <= 0){
//卖完了
break;
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + count + "张");
}
}
}
}
}
同步方法
同步方法的锁对象是this
private synchronized boolean synchronizedMethod() {
if (ticketCount <= 0){
//卖完了
return true;
} else {
try {
Thread.sleep(100);
} catch (Exception e){
e.printStackTrace();
}
ticketCount--;
System.out.println(Thread.currentThread().getName() + "在卖票" + "还剩下" + ticketCount + "张");
return true;
}
}
lock锁
ReentrantLock锁有更灵活的锁定机制,公平性选项,允许在不同的代码块之间显式地锁定和解锁,支持条件变量这些特性使ReentrantLock更适合处理复杂的同步需求和高并发环境。
package com.itheima.threaddemo10;
import java.util.concurrent.locks.ReentrantLock;
public class Ticket implements Runnable{
private int ticker = 100;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();
if (ticker <= 0){
break;
} else {
Thread.sleep(100);
ticker--;
System.out.println(Thread.currentThread().getName() + "正在卖票, " + "还剩" + ticker + "张票");
}
} catch (InterruptedException e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
死锁
锁的嵌套是一个常见的死锁原因
所以我们千万不能写锁的嵌套
Object lockA = new Object();
Object lockB = new Object();
new Thread(() -> {
while (true){
synchronized (lockA){
//线程一
synchronized (lockB){
System.out.println("小康同学正在走路");
}
}
}
}).start();
new Thread(() -> {
while (true){
synchronized (lockB){
//线程二
synchronized (lockA){
System.out.println("小薇同学正在走路");
}
}
}
}).start();
生产者和消费者
//套路:
//1. while(true)死循环
//2. synchronized 锁,锁对象要唯一
//3. 判断,共享数据是否结束. 结束
//4. 判断,共享数据是否结束. 没有结束
package com.itheima.threaddemo12;
public class Desk {
//定义一个标记flag 如果为true则表示桌上有汉堡包 此时允许吃货执行 反之则允许厨师做汉堡
public static Boolean flag = false;
//汉堡包的总数量
public static int count = 10;
//锁
public static final Object lock = new Object();
}
package com.itheima.threaddemo12;
public class Foodie extends Thread{
// 1,判断桌子上是否有汉堡包。
// 2,如果没有就等待。
// 3,如果有就开吃
// 4,吃完之后,桌子上的汉堡包就没有了
// 叫醒等待的生产者继续生产
// 汉堡包的总数量减一
@Override
public void run() {
while (true){
synchronized (Desk.lock){
if (Desk.count == 0){
System.out.println("再吃就要撑死了!");
break;
}else {
if (Desk.flag){//桌子上有汉堡的情况
System.out.println("黄乘明在吃汉堡");
Desk.flag = false;
Desk.count--;
Desk.lock.notifyAll();
}else {//桌子上没汉堡的情况
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
package com.itheima.threaddemo12;
public class Cooker extends Thread{
@Override
public void run() {
while (true){
synchronized (Desk.lock){
if (Desk.count == 0){
System.out.println("黄乘明已经吃饱了");
break;
} else {
if (!Desk.flag){
System.out.println("厨师正在做汉堡");
Desk.flag = true;
Desk.lock.notifyAll();
}else {
try {
Desk.lock.wait();
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
}
}
7.43万字了୧(๑•̀⌄•́๑)૭
发来贺电