zoukankan      html  css  js  c++  java
  • 多线程

    1、线程的使用

    1、创建:

    继承线程接口:extends Thread

    实现运行接口:implements Runnable

    使用Callable和futrue创建线程:

    package com.zhou.controller;
    
    public class Window extends Thread {
    
        private int ticket = 100;
    
        public static void main(String[] args) {
    
            Window window = new Window();
    
            // 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();
        }
    
        @Override
        public void run() {
            while (true) {
                if (ticket > 0) {
    
                    try {
                        Thread.sleep(100L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                    ticket--;
                }
            }
        }
    }
    
    

    结果:

    ...
    ... 
    ...
    ... 
    窗口1:卖票,票号为:7
    窗口3:卖票,票号为:6
    窗口2:卖票,票号为:5
    窗口1:卖票,票号为:4
    窗口1:卖票,票号为:4
    窗口2:卖票,票号为:2
    窗口1:卖票,票号为:1
    窗口3:卖票,票号为:0
    窗口2:卖票,票号为:-1
    

    2、同步机制

    1、方式一:同步代码块(synchronized)

    synchronized(同步监视器) {
    	
    }
    
    1. 说明:操作共享数据的代码即为需要被同步的代码。
    2. 共享数据:多个线程共同操作的变量。比如:ticket
    3. 同步监控器:俗称“”,任何一个类的对象都可以充当锁。

    这里使用 new Object()对象充当锁,

    synchronized(object){ ..//锁住这里的代码块..}

    为了确保三个windows 对象使用的是同一个锁,必须进行obj对象的唯一和改为static静态的。

    package com.zhou.controller;
    
    public class Window extends Thread {
    
        private int ticket = 100;
        private static Object obj = new Object();
    
        public static void main(String[] args) {
    
            Window window = new Window();
    
            // 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();
        }
    
        @Override
        public void run() {
            while (true) {
                synchronized(obj) {
                    if (ticket > 0) {
    
                        try {
                            Thread.sleep(100L);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                        System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                        ticket--;
                    }else {
                        break;
                    }
                }
            }
        }
    }
    
    

    问题:为什么不把while(true)锁进去,锁住的话只有一个窗口在执行。

    2、方式二:锁代码块(synchronized)

    package com.zhou.controller;
    
    public class Window extends Thread {
    
        private static int ticket = 100;
    
        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();
    
    
    
        }
    
        @Override
        public void run() {
            while (true) {
                show();
            }
        }
    
        private static synchronized void show() {
            if (ticket > 0) {
    
                try {
                    Thread.sleep(100L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                ticket--;
            }
        }
    }
    
    

    总结:

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

    3、方式三:lock锁

    创建锁 :private Reentranlock lock = new ReentranLock();

    手动开启和关闭锁:try{ lock.lock(); // 开锁 } finally { lock.unlock(); // 关锁}

    package com.zhou.controller;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Window extends Thread {
    
        private static int ticket = 100;
        private ReentrantLock lock = new ReentrantLock();
    
        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();
    
    
    
        }
    
        @Override
        public void run() {
            while (true) {
    
                try {
                    lock.lock(); // 手动调用lock锁
    
                    if (ticket > 0) {
    
                        try {
                            Thread.sleep(100L);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                        System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                        ticket--;
                    }
                } finally {
                    lock.unlock(); // 手动解锁
                }
    
            }
        }
    }
    
    

    3、synchronized和lock方式的异同

    相同:二者都可以解决线程安全问题

    不同:

    synchronized 执行相应代码后,自动四方同步监听器。

    lock 需要手动启动同步lock(),同步结束后也需要手动实现unlock();

    4、线程的5中状态:

    1、初始(new)

    刚创建的线程

    2、就绪(Runnable):调用了start()

    线程被其他线程调用了该线程对象的start()方法进入就绪状态等待cpu随机的时间调用线程的run()方法

    3、运行(Running):线程获得cpu时间片(timeslice)

    正在执行程序代码

    4、阻塞(Blocked):因某种原因放弃cpu使用权(wait()、sleep())

    放弃cpu使用权:让出了cpu timeslice,暂时停止运行,直到线程进入就绪(Runnable)状态,才有机会再次获得cpu timeslice,然后转到运行(Running)状态。

    1、等待阻塞:线程执行了.wait()方法。

    jvm把该线程放入到等待队列(waitting queue)中

    2、同步阻塞:获取对象同步锁时,该锁被其他线程占用。

    jvm把该线程放入锁池(lock pool)中

    3、其他阻塞:运行(running)的线程执行 sleep()、t.join()方法。

    5、死亡(Dead):线run()、main()方法执行结束。

  • 相关阅读:
    transform.forward和vector3.forward
    游戏开发数值公式
    类的大小
    c#扩展方法
    C# 线程本地存储 调用上下文 逻辑调用上下文
    DbCommandInterceptor抓取EF执行时的SQL语句
    C# 关键字const与readonly的区别
    Swagger(webapi自动生成接口说明文档)
    log4net配置
    JavaScript代码优化指南
  • 原文地址:https://www.cnblogs.com/zhouyongyin/p/13541462.html
Copyright © 2011-2022 走看看