Java多线程(全知识点)(下)

简介: Java多线程(全知识点)(下)

Java多线程(全知识点)(上):https://developer.aliyun.com/article/1419402

线程同步


案例卖票

学习代码:

public class MyThreadDemo {
    public static class SellTicket implements Runnable{
        // 默认有100张票
        private int ticket = 100;
        @Override
        public void run() {
            while (true){
                if (ticket > 0){
                    System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                    ticket --;
                }
            }
        }
    }
    public static void main(String[] args){
        SellTicket st = new SellTicket();
        // 定义对象
        Thread t1 = new Thread(st,"窗口1");
        Thread t2 = new Thread(st,"窗口2");
        Thread t3 = new Thread(st,"窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

运行结果:

改进之后的思考

学习代码:

public class MyThreadDemo {
    public static class SellTicket implements Runnable{
        private int ticket = 100;
        @Override
        public void run() {
            while (true){
                if (ticket > 0){
                    try {  // 卖票的时候 添加休眠
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                    ticket --;
                }
            }
        }
    }
    public static void main(String[] args){
        SellTicket st = new SellTicket();
        Thread t1 = new Thread(st,"窗口1");
        Thread t2 = new Thread(st,"窗口2");
        Thread t3 = new Thread(st,"窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

运行结果:

出现问题:

原因分析:

  1. 出现相同的票

  2. 出现负数的票

安全问题的解决方案

学习代码:

public class MyThreadDemo {
        public static class SellTicket implements Runnable{
            private int ticket = 100;
            private Object obj = new Object();  // 在外面定义这个Object对象
            @Override
            public void run() {
                while (true){
                    synchronized (obj){  // 不要在这里面定义这个对象 不然3个进程会产生3把锁 还是不能解决问题
                        if (ticket > 0){
                            try {  // 卖票的时候 添加休眠
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                            ticket --;
                        }
                    }
                }
            }
        }
        public static void main(String[] args){
            SellTicket st = new SellTicket();
            Thread t1 = new Thread(st,"窗口1");
            Thread t2 = new Thread(st,"窗口2");
            Thread t3 = new Thread(st,"窗口3");
            t1.start();
            t2.start();
            t3.start();
        }
    }

运行结果:

同步方法

非静态的锁

学习代码:

public class MyThreadDemo {
        public static class SellTicket implements Runnable{
            private int ticket = 100;
            private int x = 0;
            @Override
            public void run() {
                try {  // 卖票的时候 添加休眠
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                while (true){
                    if (x % 2  == 0){
                        synchronized (this){  // 非静态用的this这个锁
                            if (ticket > 0){
                                try {
                                    Thread.sleep(100);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                                ticket --;
                            }
                        }
                    } else {
                        sellTicket();
                    }
                }
            }
            private synchronized void sellTicket(){
                if (ticket > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                    ticket --;
                }
            }
        }
        public static void main(String[] args){
            SellTicket st = new SellTicket();
            Thread t1 = new Thread(st,"窗口1");
            Thread t2 = new Thread(st,"窗口2");
            Thread t3 = new Thread(st,"窗口3");
            t1.start();
            t2.start();
            t3.start();
        }
    }

运行结果:

静态方法的锁

学习代码:

public class SellTicket implements Runnable{
    private static int ticket = 100;
    private int x = 0;
    @Override
    public void run() {
        try {  // 卖票的时候 添加休眠
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (true){
            if (x % 2  == 0){
                synchronized (SellTicket.class){  // 静态的用这个锁
                    if (ticket > 0){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
                        ticket --;
                    }
                }
            } else {
                sellTicket();
            }
        }
    }
    private static synchronized void sellTicket(){
        if (ticket > 0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
            ticket --;
        }
    }
线程安全的类

案例:生产者与消费者

学习代码:

package Safe;
    public class MyThreadDemo {
        // 生产者类
        public static class Producer implements Runnable{
            private Box b;
            public Producer(Box b) {
                this.b = b;
            }
            @Override
            public void run() {
                for (int i = 1; i <= 5; ++ i){ // 放置牛奶
                    b.put(i);
                }
            }
        }
        // 消费者类
        public static class Customer implements Runnable{
            private Box b;
            public Customer(Box b) {
                this.b = b;
            }
            @Override
            public void run() {  // 获取牛奶
                while(true){
                    b.get();
                }
            }
        }
        // 奶箱类
        public static class Box{
            // 定义一个成员变量 表示第x瓶牛奶
            private int milk;
            // 定义一个成员变量,表示奶箱的状态
            private boolean state = false;
            // 提供存储牛奶和获取牛奶的操作
            // 存储牛奶
            public synchronized void put(int milk){
                // 如果有牛奶,等待消费
                if (state){
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 如果没有牛奶,就生产牛奶
                this.milk = milk;
                System.out.println("送奶工将第"+this.milk+"瓶奶放入奶箱");
                // 生产完毕之后,修改奶箱状态
                state = true;
                // 唤醒其他等待线程
                notifyAll();
            }
            // 获取牛奶
            public synchronized void get(){
                // 如果没有牛奶,等待生产
                if(!state){
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 如果有牛奶,就消费牛奶
                System.out.println("用户拿到第"+this.milk+"瓶奶");
                // 消费完毕之后,修改奶箱状态
                state = false;
                // 唤醒其他等待线程
                notifyAll();
            }
        }
        public static void main(String[] args){
            // 创建奶箱对象,这是共享数据区域
            Box b = new Box();
            // 创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类种要调用存储牛奶的操作
            Producer p = new Producer(b);
            // 创建消费者对象,把牛奶对象作为构造方法参数传递,因为在这个类种要调用获取牛奶的操作
            Customer c = new Customer(b);
            // 创建两个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
            Thread t1 = new Thread(p);
            Thread t2 = new Thread(c);
            // 启动线程
            t1.start();
            t2.start();
        }
    }

运行结果:

Lock锁

学习代码:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
    public static class SellTicket implements Runnable{
        private int ticket = 100;
        private Lock lock = new ReentrantLock();
        @Override
        public void run() {
            while(true){
                try {
                    lock.lock();
                    if (ticket > 0){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
                        ticket--;
                    }
                } finally {  // 为了使得这个锁怎么都可以释放 所以要用到finally关键字
                    lock.unlock();     
                }
            }
        }
    }
    public static void main(String[] args){
        SellTicket st = new SellTicket();
        Thread t1 = new Thread(st, "窗口一");
        Thread t2 = new Thread(st, "窗口二");
        Thread t3 = new Thread(st, "窗口三");
        t1.start();
        t2.start();
        t3.start();
    }
}

运行结果:

相关文章
|
4天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
23 9
|
7天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
4天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
7天前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
21 3
|
6天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
7天前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
17 1
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
41 1
C++ 多线程之初识多线程
|
22天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
16 3
|
22天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
15 2
|
22天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
28 2