多线程(下)(Multithreading (Part 2))

多线程(下)

线程的同步

  • 例:卖票问题:创建三个窗口卖票,总票数为100张,使用实现Runnable接口的方式

    问题:卖票过程中,出现了重票、错票–>出现了线程的安全问题
    问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票
    如何解决:当一个线程在操作ticket的时候,其他线程不能参与进来。直到线程操作完ticket时,其他线程才可以开始操作ticket。这种情况即使线程出现了阻塞也不能改变。
    在Java中,我们通过同步机制,来解决线程安全问题

    方式一:同步代码块
    synchronized(同步监视器){
    //需要被同步的代码
    }
    说明:1.操作共享数据的代码,即为需要被同步的代码 2.共享数据: 多个线程共同操作的变量 比如ticket 3.同步监视器,俗称,锁。任何一个类的对象,都可以充当锁(锁的要求:多个线程必须要公用同一把锁。4.在实现Runnable接口创建多线程的方式中,可以使用this充当同步监视器5.在使用Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器
    方式二:同步方法:如果操作共享数据 代码完整的声明在一个方法中,我们不妨将此方法声明为同步的
    总结:使用同步方法的总结

    同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
    非静态的同步方法,同步监视器是:当前类本身

    同步的方式,解决了线程的安全问题。—好处,操作同步代码时,只能有一个线程参与,其他线程等待,相当于是一个单线程过程,效率低。—局限性

  • 问题:卖票过程中,出现了重票、错票–>出现了线程的安全问题
  • 问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票
  • 如何解决:当一个线程在操作ticket的时候,其他线程不能参与进来。直到线程操作完ticket时,其他线程才可以开始操作ticket。这种情况即使线程出现了阻塞也不能改变。
  • 在Java中,我们通过同步机制,来解决线程安全问题

    方式一:同步代码块
    synchronized(同步监视器){
    //需要被同步的代码
    }
    说明:1.操作共享数据的代码,即为需要被同步的代码 2.共享数据: 多个线程共同操作的变量 比如ticket 3.同步监视器,俗称,锁。任何一个类的对象,都可以充当锁(锁的要求:多个线程必须要公用同一把锁。4.在实现Runnable接口创建多线程的方式中,可以使用this充当同步监视器5.在使用Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器
    方式二:同步方法:如果操作共享数据 代码完整的声明在一个方法中,我们不妨将此方法声明为同步的
    总结:使用同步方法的总结

    同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
    非静态的同步方法,同步监视器是:当前类本身

  • 方式一:同步代码块
    synchronized(同步监视器){
    //需要被同步的代码
    }
    说明:1.操作共享数据的代码,即为需要被同步的代码 2.共享数据: 多个线程共同操作的变量 比如ticket 3.同步监视器,俗称,锁。任何一个类的对象,都可以充当锁(锁的要求:多个线程必须要公用同一把锁。4.在实现Runnable接口创建多线程的方式中,可以使用this充当同步监视器5.在使用Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器
  • 方式二:同步方法:如果操作共享数据 代码完整的声明在一个方法中,我们不妨将此方法声明为同步的
    总结:使用同步方法的总结

    同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
    非静态的同步方法,同步监视器是:当前类本身

  • 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
  • 非静态的同步方法,同步监视器是:当前类本身
  • 同步的方式,解决了线程的安全问题。—好处,操作同步代码时,只能有一个线程参与,其他线程等待,相当于是一个单线程过程,效率低。—局限性
//关于卖票解决线程安全问题(Runnable)
public class WindowTest1 {
    public static void main(String[] args) {
        Window window = new Window();
        Thread t1 = new Thread(window);
        Thread t2 = new Thread(window);
        Thread t3 = new Thread(window);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window implements Runnable{
    private int ticket=100;
    //创建一个对象
//    Object obj = new Object();
    @Override
    public void run() {
        while (true){
            //第一种,加入一个对象。注意:同步代码块需要使用同一个对象来加锁
//            synchronized (obj){
            //第二种,使用自身对象
            synchronized (this){
                if (ticket>0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"卖"+ticket+"号票");
                    ticket--;
                }else{
                    break;
                }
            }
        }
    }
}
//Thread方式
public class WindowTest2 {
    public static void main(String[] args) {
        Window2 w1 = new Window2();
        Window2 w2 = new Window2();
        Window2 w3 = new Window2();
        w1.setName("线程一");
        w2.setName("线程二");
        w3.setName("线程三");
        w1.start();
        w2.start();
        w3.start();
    }
}
class Window2 extends Thread{
    public static int ticket= 100;
    public static Object obj = new Object();

    @Override
    public void run() {
            while (true){
        //加锁采用对象方式
//        synchronized (obj){
        synchronized (Window2.class){//Window2.class只会加载一次

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (ticket>0){
                    System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票");
                    ticket--;
                }else{
                    break;
                }
        }

        }
    }
}
//使用同步方法解决实现Runnable接口的线程安全问题
public class WindowTest3 {
    public static void main(String[] args) {
        Window3 w = new Window3();
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window3 implements Runnable{
    private int ticket = 100;

    @Override
    public void run() {
        while (ticket>0){
            show();
        }
    }
    private synchronized void show(){//同步监视器---this
        //相当于synchronized(this){
        if (ticket>0){
            System.out.println(Thread.currentThread().getName()+"卖出第"+ticket+"张票");
            ticket--;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//使用同步方法处理继承Thread类的方式中的线程安全问题
public class WindowTest4 {
    public static void main(String[] args) {
        Window4 w1 = new Window4();
        Window4 w2 = new Window4();
        Window4 w3 = new Window4();
        w1.setName("窗口一");
        w2.setName("窗口二");
        w3.setName("窗口三");
        w1.start();
        w2.start();
        w3.start();
    }
}
class Window4 extends Thread{
    private static int ticket = 1000;

    @Override
    public void run() {
        while (ticket>0){
            show();
        }
    }
    private static synchronized void show(){//同步监视器:Window4.class
        if (ticket>0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"卖出第"+ticket+"票");
            ticket--;
        }
    }
}

————————

Multithreading (Part 2)

Thread synchronization

  • Example: ticket selling problem: create three windows to sell tickets, with a total number of 100 tickets. Use the method of implementing runnable interface
    Problem: in the process of selling tickets, there are duplicate tickets and wrong tickets — > there are thread safety problems
    When a thread is not involved in the operation, the reason is: when the other thread is not involved in the operation, the reason also occurs
    How to solve it: when a thread is operating a ticket, other threads cannot participate. No other thread can start to operate the ticket until the thread has finished operating the ticket. This situation cannot be changed even if the thread is blocked.
    In Java, we use synchronization mechanism to solve thread safety problems
    Method 1: synchronize code blocks
    Synchronized (synchronized monitor){
    //Code to be synchronized
    }
    Description: 1 The code that operates the shared data is the code that needs to be synchronized 2 Shared data: variables operated by multiple threads, such as ticket 3 Synchronous monitor, commonly known as lock. The object of any class can be used as a lock (lock requirement: multiple threads must share the same lock). 4. In the way of creating multithreads by implementing runnable interface, this can be used as the synchronization monitor. 5. In the way of creating multithreads by using thread class, this should be used carefully as the synchronization monitor, and the current class should be used as the synchronization monitor
    Method 2: synchronization method: if the operation shared data code is completely declared in a method, we might as well declare this method as synchronous
    Summary: summary of using synchronization method
    The synchronization method still involves the synchronization monitor, but we don’t need to declare it explicitly.
    Non static synchronization method. The synchronization monitor is the current class itself
    The way of synchronization solves the problem of thread safety— The advantage is that when operating synchronous code, only one thread can participate and other threads wait, which is equivalent to a single threaded process with low efficiency— limitations
  • Problem: in the process of selling tickets, there are duplicate tickets and wrong tickets — > there are thread safety problems
  • When a thread is not involved in the operation, the reason is: when the other thread is not involved in the operation, the reason also occurs
  • How to solve it: when a thread is operating a ticket, other threads cannot participate. No other thread can start to operate the ticket until the thread has finished operating the ticket. This situation cannot be changed even if the thread is blocked.
  • In Java, we use synchronization mechanism to solve thread safety problems
    Method 1: synchronize code blocks
    Synchronized (synchronized monitor){
    //Code to be synchronized
    }
    Description: 1 The code that operates the shared data is the code that needs to be synchronized 2 Shared data: variables operated by multiple threads, such as ticket 3 Synchronous monitor, commonly known as lock. The object of any class can be used as a lock (lock requirement: multiple threads must share the same lock). 4. In the way of creating multithreads by implementing runnable interface, this can be used as the synchronization monitor. 5. In the way of creating multithreads by using thread class, this should be used carefully as the synchronization monitor, and the current class should be used as the synchronization monitor
    Method 2: synchronization method: if the operation shared data code is completely declared in a method, we might as well declare this method as synchronous
    Summary: summary of using synchronization method
    The synchronization method still involves the synchronization monitor, but we don’t need to declare it explicitly.
    Non static synchronization method. The synchronization monitor is the current class itself
  • Method 1: synchronize code blocks
    Synchronized (synchronized monitor){
    //Code to be synchronized
    }
    Description: 1 The code that operates the shared data is the code that needs to be synchronized 2 Shared data: variables operated by multiple threads, such as ticket 3 Synchronous monitor, commonly known as lock. The object of any class can be used as a lock (lock requirement: multiple threads must share the same lock). 4. In the way of creating multithreads by implementing runnable interface, this can be used as the synchronization monitor. 5. In the way of creating multithreads by using thread class, this should be used carefully as the synchronization monitor, and the current class should be used as the synchronization monitor
  • Method 2: synchronization method: if the operation shared data code is completely declared in a method, we might as well declare this method as synchronous
    Summary: summary of using synchronization method
    The synchronization method still involves the synchronization monitor, but we don’t need to declare it explicitly.
    Non static synchronization method. The synchronization monitor is the current class itself
  • The synchronization method still involves the synchronization monitor, but we don’t need to declare it explicitly.
  • Non static synchronization method. The synchronization monitor is the current class itself
  • The way of synchronization solves the problem of thread safety— The advantage is that when operating synchronous code, only one thread can participate and other threads wait, which is equivalent to a single threaded process with low efficiency— limitations
//关于卖票解决线程安全问题(Runnable)
public class WindowTest1 {
    public static void main(String[] args) {
        Window window = new Window();
        Thread t1 = new Thread(window);
        Thread t2 = new Thread(window);
        Thread t3 = new Thread(window);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window implements Runnable{
    private int ticket=100;
    //创建一个对象
//    Object obj = new Object();
    @Override
    public void run() {
        while (true){
            //第一种,加入一个对象。注意:同步代码块需要使用同一个对象来加锁
//            synchronized (obj){
            //第二种,使用自身对象
            synchronized (this){
                if (ticket>0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"卖"+ticket+"号票");
                    ticket--;
                }else{
                    break;
                }
            }
        }
    }
}
//Thread方式
public class WindowTest2 {
    public static void main(String[] args) {
        Window2 w1 = new Window2();
        Window2 w2 = new Window2();
        Window2 w3 = new Window2();
        w1.setName("线程一");
        w2.setName("线程二");
        w3.setName("线程三");
        w1.start();
        w2.start();
        w3.start();
    }
}
class Window2 extends Thread{
    public static int ticket= 100;
    public static Object obj = new Object();

    @Override
    public void run() {
            while (true){
        //加锁采用对象方式
//        synchronized (obj){
        synchronized (Window2.class){//Window2.class只会加载一次

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (ticket>0){
                    System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票");
                    ticket--;
                }else{
                    break;
                }
        }

        }
    }
}
//使用同步方法解决实现Runnable接口的线程安全问题
public class WindowTest3 {
    public static void main(String[] args) {
        Window3 w = new Window3();
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window3 implements Runnable{
    private int ticket = 100;

    @Override
    public void run() {
        while (ticket>0){
            show();
        }
    }
    private synchronized void show(){//同步监视器---this
        //相当于synchronized(this){
        if (ticket>0){
            System.out.println(Thread.currentThread().getName()+"卖出第"+ticket+"张票");
            ticket--;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//使用同步方法处理继承Thread类的方式中的线程安全问题
public class WindowTest4 {
    public static void main(String[] args) {
        Window4 w1 = new Window4();
        Window4 w2 = new Window4();
        Window4 w3 = new Window4();
        w1.setName("窗口一");
        w2.setName("窗口二");
        w3.setName("窗口三");
        w1.start();
        w2.start();
        w3.start();
    }
}
class Window4 extends Thread{
    private static int ticket = 1000;

    @Override
    public void run() {
        while (ticket>0){
            show();
        }
    }
    private static synchronized void show(){//同步监视器:Window4.class
        if (ticket>0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"卖出第"+ticket+"票");
            ticket--;
        }
    }
}