多线程的6个综合练习

简介: 多线程的6个综合练习


练习1

错误写法

public class MyRunnable implements Runnable {
 
    int ticket=0;
 
    @Override
    public void run() {
        //循环
        //同步代码块
        //判断共享数据是否到了末尾,如果到了末尾
        //判断共享数据是否到了末尾,如果没有到末尾
        while(true){
            if (extracted()) break;
        }
    }
 
    private  synchronized  boolean extracted() {
        if (ticket==100){
            return true;
        }
        else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket++;
            System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
        }
        return false;
    }
}
public class Main {
    public static void main(String[] args) {
 
        MyRunnable mr=new MyRunnable();
 
        //mr是唯一的 锁对象就是唯一的
        Thread t1=new Thread(mr);
        Thread t2=new Thread(mr);
 
        t1.setName("窗口1");
        t2.setName("窗口2");
 
        t1.start();
        t2.start();
    }
}

extracted方法中,使用synchronized关键字修饰,确保了线程安全,即在同一时刻只有一个线程可以执行该方法。方法中首先判断是否已经卖完了100张票,如果是则返回true,表示卖票结束;否则,通过Thread.sleep(100)方法模拟售票过程中的一些耗时操作,然后增加ticket的值,表示卖出一张票,并打印出当前卖出的票的信息。最后返回false,表示还未卖完所有的票。

在多核处理器上,不同的线程可以同时在不同的核心上执行,因此一个线程抢到了一个核心的执行权不会直接导致其他线程阻塞,除非线程之间有共享资源竞争或者其他需要同步的操作。

在上述代码中,当一个线程抢到了CPU的执行权时,由于extracted方法使用了synchronized关键字修饰,保证了在同一时刻只有一个线程能够执行该方法。因此,其他线程会在尝试执行该方法时被阻塞,直到当前执行的线程执行完毕释放锁。

具体来说,在extracted方法中,通过synchronized关键字确保了在同一时刻只有一个线程能够进入该方法执行,其他线程在尝试进入该方法时会被阻塞,直到当前线程执行完毕释放锁。因此,在这段代码中,其他线程会在某一线程执行extracted方法时被阻塞。

但是,Thread.sleep()方法并不会释放锁,因此即使一个线程在执行Thread.sleep()方法时,其他线程仍然无法进入被synchronized修饰的同步方法或代码块。

换句话说,即使一个线程在执行Thread.sleep()时,其他线程也无法执行extracted方法,直到当前线程执行完毕并释放了锁。因此,其他线程在执行extracted方法时仍然会被阻塞,直到当前线程执行完毕。

正确写法

public class MyRunnable implements Runnable {
    int ticket=0;
 
    @Override
    public void run() {
        while (true){
            synchronized (MyRunnable.class){
                if(ticket==100){
                    break;
                }
                else {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    ticket++;
                    System.out.println(Thread.currentThread().getName()+"正在售出第"+ticket+"张票");
                }
            }
        }
    }
}
public class Main {
    public static void main(String[] args) {
 
        MyRunnable mr=new MyRunnable();
 
        //mr是唯一的 锁对象就是唯一的
        Thread t1=new Thread(mr);
        Thread t2=new Thread(mr);
 
        t1.setName("窗口1");
        t2.setName("窗口2");
 
        t1.start();
        t2.start();
    }
}

练习2

你抢一我抢一解法

public class MyRunnable implements Runnable {
    int gift=100;
 
    @Override
    public void run() {
        while(true){
            synchronized (MyRunnable.class){
                if(gift<=10)break;
                else {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    gift--;
                    System.out.println(Thread.currentThread().getName()+"抢到了第"+(100-gift)+"个礼物");
                }
                MyRunnable.class.notifyAll();//唤醒正在等待的线程
                try {
                    MyRunnable.class.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
public class Main {
    public static void main(String[] args) {
 
        MyRunnable mr=new MyRunnable();
 
        //mr是唯一的 锁对象就是唯一的
        Thread t1=new Thread(mr);
        Thread t2=new Thread(mr);
 
        t1.setName("小明");
        t2.setName("小红");
 
        t1.start();
        t2.start();
    }
}

练习3

标准写法

public class MyRunnable implements Runnable {
    int i=0;
 
    @Override
    public void run() {
        while(true){
            synchronized (MyRunnable.class){
                i++;
                if(i>=100)break;
                else {
                    if(i%2!=0){
                        System.out.println(Thread.currentThread().getName()+"获取了奇数"+i);
                    }
                }
            }
        }
    }
}
public class Main {
    public static void main(String[] args) {
 
        MyRunnable mr=new MyRunnable();
 
        //mr是唯一的 锁对象就是唯一的
        Thread t1=new Thread(mr);
        Thread t2=new Thread(mr);
 
        t1.setName("线程1");
        t2.setName("线程2");
 
        t1.start();
        t2.start();
    }
}

高级写法

线程1首先将锁的对象执行wait()方法 进入沉睡

当线程2将锁对象执行方法notifyAll()时 线程1就会到达锁的外面

以此反复

练习4

import java.util.Random;
 
public class hongbao extends Thread{
 
    static double money=100;
    static int count=3;
    static final double MIN=0.01;
 
    public hongbao(String name) {
        this.setName(name);
    }
    public hongbao() {
    }
 
    @Override
    public void run() {
        /*
        *同步代码块
        *判断 共享数据是否到末尾 是
        *判断 共享数据是否到末尾 否
        * */
        synchronized (hongbao.class){
            if(count==0){
                System.out.println(getName()+"没有抢到红包");
            }else {
                double price=0;
                if(count==1){
                    //表示此时是最后一个红包 剩余的所有钱都是中奖金额
                    price=money;
                } else{
                    //表示不是最后一个红包 获取随机带小数
                    Random r=new Random();
                    price=r.nextDouble(money-(count-1)*MIN);
                    if(price<MIN)price=0.01;
                }
                money-=price;
                count--;
                System.out.println(getName()+"抢到了"+price+"元的红包");
            }
        }
    }
}
public class Main {
    public static void main(String[] args) {
        new hongbao("小岩").start();
        new hongbao("小栾").start();
        new hongbao("小畅").start();
        new hongbao("小于").start();
        new hongbao("小烨").start();
    }
}

练习5

import java.util.Random;
 
public class MyRunnable implements Runnable {
    int arr[]=new int[]{10,5,20,50,100,200,500,800,2,80,300,700};
    @Override
    public void run() {
        while(true){
            synchronized (MyRunnable.class){
                Random r=new Random();
                int RanNumber=r.nextInt(12);//获得0-11的随机整数
                System.out.println(Thread.currentThread().getName()+"获得了"+arr[RanNumber]+"元");
            }
        }
    }
}
public class Main {
    public static void main(String[] args) {
 
        MyRunnable mr=new MyRunnable();
 
        //mr是唯一的 锁对象就是唯一的
        Thread t1=new Thread(mr);
        Thread t2=new Thread(mr);
 
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");
 
        t1.start();
        t2.start();
    }
}

练习6

import java.util.Random;
 
public class MyRunnable implements Runnable {
    int arr1[]=new int[]{10,20,100,500,2,300};
    int arr2[]=new int[]{5,50,200,800,80,700};
    int t1=6;
    int t2=6;
    int t1Sum=0;
    int t2Sum=0;
    boolean t1Judge=false;
    boolean t2Judge=false;
 
    @Override
    public void run() {
        while(true){
            synchronized (MyRunnable.class){
                Random r=new Random();
                int RanNumber=r.nextInt(6);//获得0-5的随机整数
                if(Thread.currentThread().getName()=="抽奖箱1"){
                    if(t1==0){
                        if(t2Judge)break;
                        System.out.println("抽奖结束抽奖箱1获得的总金额为"+t1Sum+"元");
                        t2Judge=true;
                    }
                    else {
                        System.out.println(Thread.currentThread().getName()+"获得了"+arr1[RanNumber]+"元");
                        t1--;
                        t1Sum+=arr1[RanNumber];
                    }
                }
                if(Thread.currentThread().getName()=="抽奖箱2"){
                    if(t2==0){
                        if(t1Judge)break;
                        System.out.println("抽奖结束抽奖箱2获得的总金额为"+t2Sum+"元");
                        t1Judge=true;
                    }
                    else {
                        System.out.println(Thread.currentThread().getName()+"获得了"+arr2[RanNumber]+"元");
                        t2--;
                        t2Sum+=arr2[RanNumber];
                    }
                }
                if(t1Judge&&t2Judge)
                    System.out.println(t1Sum>t2Sum?t1Sum==t2Sum?"两个抽奖箱子获得的钱一样多":"抽奖箱子1比抽奖箱2多抽"+(t1Sum-t2Sum)+"元":"抽奖箱子2比抽奖箱1多抽"+(t2Sum-t1Sum)+"元");
 
            }
        }
    }
}
public class Main {
    public static void main(String[] args) {
 
        MyRunnable mr=new MyRunnable();
 
        //mr是唯一的 锁对象就是唯一的
        Thread t1=new Thread(mr);
        Thread t2=new Thread(mr);
 
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");
 
        t1.start();
        t2.start();
    }
}

(题目和图片均来自黑马程序员 代码是自己敲的)

目录
相关文章
|
4月前
|
安全 数据安全/隐私保护 数据中心
Python并发编程大挑战:线程安全VS进程隔离,你的选择影响深远!
【7月更文挑战第9天】Python并发:线程共享内存,高效但需处理线程安全(GIL限制并发),适合IO密集型;进程独立内存,安全但通信复杂,适合CPU密集型。使用`threading.Lock`保证线程安全,`multiprocessing.Queue`实现进程间通信。选择取决于任务性质和性能需求。
88 1
|
1月前
|
安全 Java 数据库连接
Python多线程编程:竞争问题的解析与应对策略
Python多线程编程:竞争问题的解析与应对策略
18 0
|
1月前
|
安全 Java 数据库连接
Python多线程编程:竞争问题的解析与应对策略【2】
Python多线程编程:竞争问题的解析与应对策略【2】
20 0
|
4月前
|
算法 Java 编译器
多线程线程安全问题之系统层面的锁优化有哪些常见的策略
多线程线程安全问题之系统层面的锁优化有哪些常见的策略
|
4月前
|
存储 Java 调度
线程操纵术并行策略问题之Java的并行编程优势问题如何解决
线程操纵术并行策略问题之Java的并行编程优势问题如何解决
|
5月前
|
安全 Java 调度
Java并发编程:优化多线程应用的性能与安全性
在当今软件开发中,多线程编程已成为不可或缺的一部分,尤其在Java应用程序中更是如此。本文探讨了Java中多线程编程的关键挑战和解决方案,重点介绍了如何通过合理的并发控制和优化策略来提升应用程序的性能和安全性,以及避免常见的并发问题。
57 1
|
4月前
|
Java 测试技术 容器
多线程编程基础与并发问题解决方案
多线程编程基础与并发问题解决方案
|
5月前
|
缓存 并行计算 安全
【并发编程系列一】并发编年史:线程的双刃剑——从优势到风险的全面解析
【并发编程系列一】并发编年史:线程的双刃剑——从优势到风险的全面解析
|
缓存 安全 Java
从CPU的视角看 多线程代码为什么那么难写!
当我们提到多线程、并发的时候,我们就会回想起各种诡异的bug,比如各种线程安全问题甚至是应用崩溃,而且这些诡异的bug还很难复现。我们不禁发出了灵魂拷问 “为什么代码测试环境运行好好的,一上线就不行了?”。 为了解决线程安全的问题,我们的先辈们在编程语言中引入了各种各样新名词,就拿我们熟悉的Java为例,不仅java语言自带了synchronized、volatile、wait、notify… ,jdk中各种工具包也是层出不穷,就比如单一个Lock,就可以有很多种实现,甚至很多人都谈锁色变。
82 0
|
安全 算法 Java
【并发编程技术】「技术辩证分析」在并发编程模式下进行线程安全以及活跃性问题简析
【并发编程技术】「技术辩证分析」在并发编程模式下进行线程安全以及活跃性问题简析
76 0
【并发编程技术】「技术辩证分析」在并发编程模式下进行线程安全以及活跃性问题简析

相关实验场景

更多