练习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();
    }
}

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