目录
线程的简介:
多任务:
多线程:
普通方法调用
多线程:
核心概念:
线程的创建
Thread:
代码:
注意:
实现Runnable接口:
代码:
小结:
初识并发问题:
代码:
运行的结果:
龟兔赛跑:
步骤:
实现Callable接口(了解即可)
代码:
静态代理模式:
静态代理模式总结:
好处:
线程的五大状态:
方法:
线程的停止:
代码:
线程休眠:
倒计时的代码:
模拟网络延时:
线程礼让:
代码:
运行的结果是:
礼让成功:
礼让失败:
Join
代码:
线程状态观测:
代码:
线程的优先级:
注意:
代码:
运行的结果:
注意:
守护线程(daemon):
代码:
线程同步:
并发:
三大不安全例子:
不安全的买票:
不安全的取钱:
输出的结果是:
线程不安全的集合:
运行的结果:
同步方法及同步块:
同步代码的弊端:
同步块:
安全的买票:
安全的取钱:
代码:
以下是ai做出的回应:
运行的结果:
死锁:
代码:
运行的结果:
解决的方法:
运行的结果:
死锁避免的方法:
Lock锁:
代码演示:
注意事项:
synchronized和Lock的对比:
线程协作:
线程通信:
线程通信-分析:
java提供了几个方法解决线程之间的通信问题:
解决方式1:
代码:
解决方式2:
代码:
运行结果:
线程池:
使用线程池:
代码:
运行结果:
看起来是多个任务都在做,其实本质上我们的大脑在同一时间依旧只做一件事情
原来是一条道路,慢慢因为车太多了,道路堵塞,效率较低,为了提高使用的效率,能够充分利用道路,于是加了多个车道.
进程是系统分配的 进程里面有线程, 至少有一个线程(main),真正执行的是线程,真正的多线程是指有多个cpu,也就是多核,比如服务器.如果是模拟出来的线程,即在一个cpu的情况下,在同一时间点,cpu执行一个代码,因为切换的很快,所以就有同时执行的错觉.
public class MyThread extends Thread {
@Override
public void run() {
for(int i = 1; i <= 20; ++ i ) {
System.out.println("Code1: " + i );
}
}
public static void main(String[] args) {
//创建线程对象
MyThread thread = new MyThread();
//开启线程
thread.start();
for(int i = 1; i <= 20; ++ i ) {
System.out.println("Code2: " + i);
}
//以上两个线程是同时执行的 每次执行的结果都是不一样的
}
}
线程开启后,不一定立刻执行,由cpu调度安排
public class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 1; i <= 100; ++ i ) {
System.out.println("Code change the word");
}
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
for(int i = 1; i <= 100; ++ i ) {
System.out.println("我认为你说的对");
}
}
}
//多线程同时操作同一个对象
//买火车票的例子
public class TestThread implements Runnable{
private int ticketNums = 10;//票的数量
@Override
public void run() {
while (true) {
if(ticketNums <= 0) {//没票了
break;
}
System.out.println(Thread.currentThread().getName() + "购买了第" + ticketNums-- +"票");
}
}
public static void main(String[] args) {
TestThread ticket = new TestThread();
//创建买票的对象 这3个线程用这10张票
new Thread(ticket, "用户1").start();
new Thread(ticket, "用户2").start();
new Thread(ticket,"用户3").start();
}
}
发现有不同的人拿到相同的票的,也就是多个线程操作同一个资源的情况下,线程不安全,数据紊乱
public class Race implements Runnable{
private static String winner;
@Override
public void run() {
for(int i = 1; i <= 100; ++ i ) {
//模拟兔子休息
if(Thread.currentThread().getName().equals("兔子") && i % 10 == 0) {//每10步休息0.2s
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛时候结束
boolean flag = gameOver(i);
//如果比赛结束 就停止程序
if(flag) {
break;
}
System.out.println(Thread.currentThread().getName() + "-->跑了" + i + "米");
}
}
//判断是否完成比赛了
private boolean gameOver(int steps) {
if(winner != null) {
return true;
}
if(steps >= 100) {
winner = Thread.currentThread().getName();
System.out.println("胜利者是: " + winner);
return true;
}
return false;
}
public static void main(String[] args) {
Race race = new Race();//赛道只有一条
new Thread(race, "兔子").start();
new Thread(race, "乌龟").start();
}
}
//兔子睡觉了 胜利者是乌龟
package 线程;
//实现Callable接口
import java.util.concurrent.*;
public class MyCallable implements Callable {
@Override
public Integer call() throws Exception {
int sum = 0;
for(int i = 1; i <= 100; i ++ ) {
sum += i;
}
return sum;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable t1 = new MyCallable();
MyCallable t2 = new MyCallable();
MyCallable t3 = new MyCallable();
//创建执行服务 线程池
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Futureresult1 = ser.submit(t1);
Futureresult2 = ser.submit(t2);
Futureresult3 = ser.submit(t3);
//获取结果
int r1 = result1.get();
int r2 = result2.get();
int r3 = result3.get();
//关闭服务
ser.shutdownNow();
}
}
public class StaticProxy {
public static void main(String[] args) {
You you = new You();//你要结婚了
new Thread(()-> System.out.println("I love you")).start();
new WeddingCompany(new You()).HappyMarry();
}
}
interface Marry {
void HappyMarry();
}
//真实角色
class You implements Marry {
@Override
public void HappyMarry() {
System.out.println("FindYou.要结婚啦");
}
}
//代理角色 帮助你
class WeddingCompany implements Marry {
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void HappyMarry() {
before();
target.HappyMarry();//真实对象
after();
}
private void before() {
System.out.println("结婚之前,布置现场");
}
private void after() {
System.out.println("结婚之后,收尾款");
}
}
真实对象和代理对象都要实现同一个接口 代理对象要代理真实角色
代理对象可以做很多真实对象做不了的事情 真实对象专注做自己的事
//测试stop
//建议线程正常停止
//不要实现stop和destroy等过时的
public class TestStop implements Runnable {
//设置一个标识位
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag) {
System.out.println("run......Thread" + ++ i );
}
}
//转换标识位
public void stop() {
flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for(int i = 1; i <= 100; ++ i ) {
System.out.println("main" + i);
if(i == 50) {
testStop.stop();//切换标识位 停止线程
System.out.println("线程要停止啦");
}
}
}
}
//模拟倒计时
public class Sleep {
public static void tenDown() throws InterruptedException {
int num = 10;
while(true) {
Thread.sleep(1000);//线程延迟
System.out.println(num--);
if(num == 0)break;
}
}
public static void main(String[] args) throws InterruptedException {
tenDown();
}
}
放大问题的发生性
public class TestYield {
public static void main(String[] args) {
MyYield m1 = new MyYield();
MyYield m2 = new MyYield();
new Thread(m1, "m1").start();
new Thread(m2, "m2").start();
}
}
class MyYield implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程开始执行");
Thread.yield();//线程礼让
System.out.println(Thread.currentThread().getName() + "线程停止执行");
}
}
public class TestJoin implements Runnable{
@Override
public void run() {
for(int i = 1; i <= 1000; ++ i ) {
System.out.println("VIP来了" + i);
}
}
public static void main(String[] args) {
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
//主线程
for(int i = 1; i <= 500; ++ i ) {
if(i == 200) {
//插队啦 要跑完的 很霸道
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main " + i );
}
}
}
//观察测试线程的状态
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for(int i = 1; i <= 5; ++ i ) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("!!!!!!");
});
//观察启动前现成的状态
Thread.State state = thread.getState();
System.out.println(state);
//观察启动后线程的状态
thread.start();//启动线程
state = thread.getState();
System.out.println(state);
while (state != Thread.State.TERMINATED) {//只要线程不终止 就一直输出状态
Thread.sleep(100);
state = thread.getState();
System.out.println(state);
}
//线程一旦进入死亡状态就不能在启动了
}
}
优先级大,并不一定被执行,只不过概率变大了
package 线程;
public class TestPriority {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "的优先级--> " + Thread.currentThread().getPriority());//main的优先级默认是5
Thread t1 = new Thread(new myPriority());
Thread t2 = new Thread(new myPriority());
Thread t3 = new Thread(new myPriority());
Thread t4 = new Thread(new myPriority());
Thread t5 = new Thread(new myPriority());
Thread t6 = new Thread(new myPriority());
t1.start();//不设优先级
t2.setPriority(1);//设优先级为4
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);//优先级最高是10
t4.start();
t5.setPriority(11);//超出优先级的范围[1 10] 会报异常
t5.start();
t6.setPriority(0);//超出优先级的范围[1 10] 会报异常
t6.start();
}
}
class myPriority implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "的优先级--> " + Thread.currentThread().getPriority());
}
}
优先级高的并不一定先被执行
超出范围会报异常
//测试守护线程
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
You1 you1 = new You1();
Thread thread = new Thread(god);
thread.setDaemon(true);//默认是false 表示的是用户线程 正常的线程都是用户线程
thread.start();//上帝守护线程启动
//注意 虚拟机不用等待守护线程执行完毕
new Thread(you1).start();//用户线程启动...
}
}
//上帝
class God implements Runnable {
@Override
public void run() {
while(true) {
System.out.println("上帝保佑着你");
}
}
}
//你
class You1 implements Runnable {
@Override
public void run() {
for(int i = 1; i <= 36500; ++ i ) {
System.out.println("祝福各位开心度过每一天");
}
System.out.println("下辈子见 goodbye world");
}
}
//虚拟机停止 需要一点时间
多个线程操作同一个资源
//线程不安全 有重复的票被买到不同人手里面
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket, "第1个人").start();
new Thread(buyTicket, "第2个人").start();
new Thread(buyTicket, "第3个人").start();
}
}
class BuyTicket implements Runnable {
boolean flag = true;
private int ticketNums = 10;
@Override
public void run() {
while(flag) {
buy();
}
}
private void buy() {
if(ticketNums <= 0) {
flag = false;
return;
}
try {
Thread.sleep(100);//方法问题的错误性
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 买了第 " + ticketNums--);
}
}
package 线程;
public class UnsafeBank {
public static void main(String[] args) {
Account account = new Account(100, "FindYou.基金");
Drawing you = new Drawing(account, 50, "你");
Drawing him = new Drawing(account, 100, "他");
you.start();
him.start();
}
}
class Account {//账户
int monkey;
String name;
public Account(int monkey, String name) {
this.monkey = monkey;
this.name = name;
}
}
//银行 模拟取款
class Drawing extends Thread {
Account account;//账户
int drawingMoney;//取多少钱
int nowMoney;//现在手里有多少钱
public Drawing(Account account, int drawingMoney, String name) {
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//取钱
@Override
public void run() {
if(account.monkey - drawingMoney < 0 ) {
System.out.println(Thread.currentThread().getName() + " 取钱的时候,钱不够了");
return;
}
try {
//放大问题
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.monkey -= drawingMoney;
nowMoney += drawingMoney;//现在手里的钱
System.out.println(account.name + "账户还剩: " + account.monkey);
System.out.println(this.getName() + "手里的钱有: " + nowMoney);
}
}
public class UnsafeList {
public static void main(String[] args) {
Listlis = new ArrayList<>();
for(int i = 0; i <= 1000; ++ i ) {
new Thread(()->{
lis.add(Thread.currentThread().getName());
}).start();
}
System.out.println(lis.size());
}
}
有的别覆盖掉了(他们会同时进去)
package 线程;
//线程不安全 有重复的票被买到不同人手里面
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket, "第1个人").start();
new Thread(buyTicket, "第2个人").start();
new Thread(buyTicket, "第3个人").start();
}
}
class BuyTicket implements Runnable {
boolean flag = true;
private int ticketNums = 10;
@Override
public void run() {
while(flag) {
buy();
}
}
//synchronized 变成了同步方法 实现了一个锁 锁的是this
private synchronized void buy() {
if(ticketNums <= 0) {
flag = false;
return;
}
try {
Thread.sleep(100);//方法问题的错误性
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 买了第 " + ticketNums--);
}
}
安全与不安全的区别就是在买票 buy 这个方法上加上了synchronized
package 线程;
public class UnsafeBank {
public static void main(String[] args) {
Account account = new Account(100, "FindYou.基金");
Drawing you = new Drawing(account, 50, "你");
Drawing him = new Drawing(account, 100, "他");
you.start();
him.start();
}
}
class Account {//账户
int monkey;
String name;
public Account(int monkey, String name) {
this.monkey = monkey;
this.name = name;
}
}
//银行 模拟取款
class Drawing extends Thread {
Account account;//账户
int drawingMoney;//取多少钱
int nowMoney;//现在手里有多少钱
public Drawing(Account account, int drawingMoney, String name) {
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//取钱
@Override
public void run() {
synchronized (account) {
if(account.monkey - drawingMoney < 0 ) {
System.out.println(Thread.currentThread().getName() + " 取钱的时候,钱不够了");
return;
}
try {
//放大问题
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.monkey -= drawingMoney;
nowMoney += drawingMoney;//现在手里的钱
System.out.println(account.name + "账户还剩: " + account.monkey);
System.out.println(this.getName() + "手里的钱有: " + nowMoney);
}
}
}
加上了 synchronized (account){}, 这里锁的就是account了
要是直接在void run()的前面加上synchronized,是不行的
代码中的synchronized关键字用于实现同步,它可以修饰方法或者代码块,以确保在同一时刻最多只有一个线程执行该段代码。
在您提供的代码中,synchronized关键字被用来修饰run方法。这里有一个问题:虽然run方法是同步的,但是每个Drawing对象都会拥有自己的锁,因为run方法是实例方法,锁定的是调用该方法的对象(在这个情况下是Drawing对象)。由于您创建了两个不同的Drawing对象(you和him),它们各自持有不同的锁,所以这两个线程仍然可以同时进入各自的run方法。
要正确地同步对Account对象的访问,您需要确保所有线程都使用同一个锁。在这种情况下,最合适的锁对象是共享资源Account对象本身。您可以通过同步一个代码块,并使用account作为锁对象来实现这一点。
// 死锁: 多个线程相互抱着对方需要的资源,然后形成僵持
public class DeadLock {
public static void main(String[] args) {
Makeup m1 = new Makeup(0, "灰姑娘");
Makeup m2 = new Makeup(1, "白雪公主");
m1.start();
m2.start();
}
}
// 口红
class Lipstick {
}
// 镜子
class Mirror {
}
// 化妆
class Makeup extends Thread {
// 需要的资源 注意只有一份
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice; // 选择
String name; // 使用化妆的人
public Makeup(int choice, String name) {
this.choice = choice;
this.name = name;
}
@Override
public void run() {
// 化妆
makeup();
}
// 化妆
private void makeup() {
if (choice == 0) {
synchronized (lipstick) { // 获得口红的锁
System.out.println(getName() + " 想获得口红的锁");
try {
Thread.sleep(1000); // 增加延迟操作
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (mirror) { // 想获得镜子的锁
System.out.println(getName() + " 想获得镜子的锁");
}
}
} else {
synchronized (mirror) { // 获得镜子的锁
System.out.println(getName() + " 想获得镜子的锁");
try {
Thread.sleep(1000); // 增加延迟操作
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lipstick) { // 想获得口红的锁
System.out.println(getName() + " 想获得口红的锁");
}
}
}
}
}
会一直卡着
程序不同时抱着对方的锁,放在外边
package 线程;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
public static void main(String[] args) {
Sale sale = new Sale();
new Thread(sale, "店铺1").start();
new Thread(sale, "店铺2").start();
new Thread(sale, "店铺3").start();
}
}
class Sale implements Runnable {
int tickets = 100;
//定义lock锁 在排队
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();//加锁
if (tickets > 0) {//注意这里要加一下 检查
System.out.println(Thread.currentThread().getName() + " 正在售卖第:" + (100 - --tickets) + "张票");
} else {
break;
}
} finally {
//解锁
lock.unlock();
}
}
}
}
在使用 ReentrantLock 时,需要注意以下几点:
生产者和消费者
//测试:生产者消费者模型-->利用缓冲区解决:管程法
//需要 生产者 消费者 产品 缓冲区
public class TestPC {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Product(container).start();
new Consumer(container).start();
}
}
//生产者
class Product extends Thread {
SynContainer container;
public Product(SynContainer container) {
this.container = container;
}
@Override
public void run() {
for(int i = 0; i < 100; ++ i ) {
System.out.println("生产了" + i + "只鸡");
container.push(new Chicken(i));
}
}
}
//消费者
class Consumer extends Thread {
SynContainer container;
public Consumer(SynContainer container) {
this.container = container;
}
@Override
public void run() {
for(int i = 0; i < 100; ++ i ) {
System.out.println("消费了-->" + container.pop().id + "只鸡");
}
}
}
//产品
class Chicken {
int id;//产品编号
public Chicken(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer {
//需要容器的大小
Chicken[] chickens = new Chicken[10];
int cnt = 0;
//生产者放入产品
public synchronized void push(Chicken chicken) {
//如果容器满了 需要等待消费者
if(cnt == chickens.length) {
//通知消费者消费
//生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没满
chickens[cnt++] = chicken;
//可以通知消费者去吃啦
this.notifyAll();
}
//消费的
public synchronized Chicken pop() {
//如果容器里面没有 唤醒厨师 让他开始做饭
if(cnt == 0) {
//等待生产者生产 消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果可以消费
this.notifyAll();
cnt--;
return chickens[cnt];
}
}
public class TestPC2 {
public static void main(String[] args) {
Tv tv = new Tv();
new Player(tv).start();
new Watcher(tv).start();
}
}
class Player extends Thread{
Tv tv;
public Player(Tv tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.play();
}
}
}
class Watcher extends Thread{
Tv tv;
public Watcher(Tv tv) {
this.tv = tv;
}
@Override
public void run() {
for(int i = 1; i <= 20; ++ i ) {
tv.watch();
}
}
}
class Tv {
boolean flag = true;
//false 表示该观众看了
//true 表示该演员表演了
public synchronized void play() {//演员表演
if(flag == false) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("表演了节目");
this.notifyAll();
this.flag = !this.flag;
}
public synchronized void watch() {
if(flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观看了节目");
//通知演员表演
this.notifyAll();
this.flag = !this.flag;
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestPool {
public static void main(String[] args) {
//创建服务 创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);//里面的参数是 线程池的大小
//把线程丢进去
service.execute(new MyThread2());
service.execute(new MyThread2());
service.execute(new MyThread2());
service.execute(new MyThread2());
//关闭链接
service.shutdown();
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " --> Code change the word");
}
}