• 编程开发之--java多线程学习总结(1)问题引入与概念叙述


    1、经典问题,火车站售票,公共票源箱,多个窗口同时取箱中车票销售

    package com.lfy.ThreadsSynchronize;
    
    /**
     * 解决办法分析:即我们不能同时让超过两个以上的线程进入到 if(num>0)的代码块中
     * 1、使用 同步代码块
    
       2、使用 同步方法
    
       3、使用 锁机制
    */
    public class TicketSell1 extends Thread{
    
        //定义一共有 50 张票,注意声明为 static,表示几个窗口共享
        private static int num = 50;
         
        //调用父类构造方法,给线程命名
        public TicketSell1(String string) {
            super(string);
        }
        
        @Override
        public void run() {
            //票分 50 次卖完
            for(int i = 0 ; i < 50 ;i ++){
                if(num > 0){
                    try {
                        Thread.sleep(10);//模拟卖票需要一定的时间
                    } catch (InterruptedException e) {
                        // 由于父类的 run()方法没有抛出任何异常,根据继承的原则,子类抛出的异常不能大于父类, 故我们这里也不能抛出异常
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+(--num)+"张");
                }
            }
        }
    }

     2、对于解决办法,java中专门提供了synchronized关键字处理多线程同步问题,有了synchronized关键字,多线程程序的运行结果将变得可以控制。synchronized关键字用于保护共享数据。synchronized实现同步的机制:synchronized依靠"锁"机制进行多线程同步,"锁"有2种,一种是对象锁,一种是类锁。synchronized关键字修饰普通方法时,获得的锁是对象锁,也就是this。而修饰静态方法时,锁是类锁,也就是类名.class。

       阻塞:A、B线程同时运行,由于锁的控制,某时刻A线程还能继续执行,B线程被挂起等待了,就说B线程被阻塞了。

    (1)对象锁,使用synchronized修饰多个普通方法,当不同线程调用同一个对象的不同被synchronized修饰过的方法时,第一个调用被synchronized修饰过的方法的线程会得到对象锁,其他线程处于阻塞状态,直至第一个得到锁的线程退出被synchronized修饰过的方法。举个例子:

    package lfy;
    
    public class TestSynchronized {
        public synchronized void method1() throws InterruptedException {
            System.out.println("method1 begin at:" + System.currentTimeMillis());
            System.out.println("method1 begin to sleep 5s");
            Thread.sleep(5000);
            System.out.println("method1 end at:" + System.currentTimeMillis());
        }
        public synchronized void method2() throws InterruptedException {
            for(int i=0;i<5;i++) {
                System.out.println("method2 running");
                Thread.sleep(200);
            }
        }
        static TestSynchronized instance = new TestSynchronized();
        public static void main(String[] args) {
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        instance.method1();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    for(int i=1; i<4; i++) {
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("Thread1 still alive");
                    }
                    System.out.println("Thread1 over");
                }
            });
            
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        instance.method2();
                        System.out.println("Thread2 over");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            
            thread1.start();
            thread2.start();    
        }
    }

    运行结果:

    解释:创建了一个对象实例instance,创建两个线程Thread1、Thread2,它们分别调用instance的mothod1、mothod2方法,由于线程1先启动并先访问到被synchronized修饰的mothod1,此时instance对mothod2上锁,线程2此时只能等待mothod2的锁被释放,才能执行mothod2方法。这就是对象锁机制。

    (2)类锁,对所有对象调用被synchronized修饰的static方法进行锁定,没有被synchronized修饰的static方法不会被上锁。

    package lfy;
    
    public class TestSynchronized {
        public synchronized static void method1() throws InterruptedException {
            System.out.println("method1 begin at:" + System.currentTimeMillis());
            System.out.println("method1 begin to sleep 5s");
            Thread.sleep(5000);
            System.out.println("method1 end at:" + System.currentTimeMillis());
        }
        public synchronized static void method2() throws InterruptedException {
            for(int i=0;i<5;i++) {
                System.out.println("method2 running");
                Thread.sleep(200);
            }
        }
        /**
         * 没有static、synchronized修饰的普通方法
         * @throws InterruptedException
         */
        public void method3() throws InterruptedException {
                System.out.println("method3 running");
                Thread.sleep(200);
        }
        /**
         * 只有synchronized修饰的普通方法
         * @throws InterruptedException
         */
        public synchronized void method4() throws InterruptedException {
                System.out.println("method4 running");
                Thread.sleep(200);
        }
        static TestSynchronized instance1 = new TestSynchronized();
        static TestSynchronized instance2 = new TestSynchronized();
        static TestSynchronized instance3 = new TestSynchronized();
        static TestSynchronized instance4 = new TestSynchronized();
        public static void main(String[] args) {
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        instance1.method1();
    //TestSynchronized.mothod1(); }
    catch (InterruptedException e) { e.printStackTrace(); } for(int i=1; i<4; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1 still alive"); } System.out.println("Thread1 over"); } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { instance2.method2();
    //TestSynchronized.mothod2(); System.out.println(
    "Thread2 over"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread3 = new Thread(new Runnable() { @Override public void run() { try { instance3.method3(); System.out.println("method3 over"); Thread.sleep(10000); System.out.println("Thread3 still alive"); System.out.println("Thread3 now to over"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread4 = new Thread(new Runnable() { @Override public void run() { try { instance4.method4(); System.out.println("method4 over"); Thread.sleep(10000); System.out.println("Thread4 still alive"); System.out.println("Thread4 now to over"); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }

    运行结果:

  • 相关阅读:
    Log4Net 全方位跟踪程序运行
    ASP.NET MVC 3和Razor中的@helper 语法
    C# 4.0四大新特性代码示例与解读
    程序员必读
    重学算法(1)--遍历二叉树
    重学算法-目录
    Epplus使用技巧
    JQuery 获取URL中传递的参数
    Epplus 使用案例
    .net调用存储过程详解(转载)
  • 原文地址:https://www.cnblogs.com/ZeroMZ/p/9292410.html
Copyright © 2020-2023  润新知