• 2019-06-03 Java学习日记之多线程下&GUI


    多线程下

    单例设计模式:

    保证类在内存中只有一个对象

    如何保证类在内存中只有一个对象呢?

      1、控制类的创建,不让其他类来创建本类的对象

      2、在本类中定义一个本类的对象,Singleton s

      3、提供公共的访问方式

    单例写法两种:

    1、饿汉式  开发用这种

    2、懒汉式  面试用这种

    3、第三种格式

    public class Demo1 {
        /**
         * 单例设计模式:保证类在内存中只有一个对象
         */
        public static void main(String[] args) {
            //Singleton s1 = new Singleton();
            
            Singleton s1 = Singleton.s;        //成员变量被私有,不能通过类名.调用        
            //Singleton.s = null;
            Singleton s2 = Singleton.s;
            
            System.out.println(s1 == s2);
            
            /*Singleton s1 = Singleton.getInstance();
            Singleton s2 = Singleton.getInstance();
            
            System.out.println(s1 == s2);*/
        }
    }
    /**
     * 饿汉式
     * @author clq
     *
     
     class Singleton {
         //1、私有构造方法,其他类不能访问该构造方法了
         private Singleton(){
             
         }
        //2、创建本类对象
        private static Singleton s = new Singleton();
        //3、对外提供公共的访问方法
        public static Singleton getInstance(){            //获取实例
            return s;
        }
     }*/
    
    /**
     * 懒汉式,单例的延迟加载模式
     * @author clq
     *
     */
     /*class Singleton {
         //1、私有构造方法,其他类不能访问该构造方法了
         private Singleton(){}
        //2、声明一个引用
        private static Singleton s;
        //3、对外提供公共的访问方法
        public static Singleton getInstance(){            //获取实例
            if (s == null) {
                //线程1等待,线程2等待
                s = new Singleton();
            }
            return s;
        }
     }*/
     /**
      * 饿汉式和懒汉式的区别:
      * 1、饿汉式是空间换时间,懒汉式是时间换空间
      * 2、在多线程访问是,饿汉式不会创建多个对象,而懒汉式有可能会创建多个对象
      * 
      */
    class Singleton {
         //1、私有构造方法,其他类不能访问该构造方法了
         private Singleton(){}
        //2、声明一个引用
        public static final Singleton s = new Singleton();
        
    }

    Runtime类:

    Runtime类是一个单例类

    import java.io.IOException;
    
    public class Demo2 {
    
        public static void main(String[] args) throws IOException {
            Runtime r = Runtime.getRuntime();            //获取运行时对象
            //r.exec("shutdown -s -t 300");
            r.exec("shutdown -a");
        }
    
    }

    Timer:

    Timer类:计时器

    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class Demo3 {
        public static void main(String[] args) throws InterruptedException {
            Timer t = new Timer();
            t.schedule(new MyTimerTask(), new Date(119,5,5,9,42,50),3000);
            //在指定时间安排指定任务
            //第一个参数,是安排的任务,第二个参数是执行的时间,第三个参数是过多长时间再重复执行
            while(true){
                Thread.sleep(1000);
                System.out.println(new Date());
            }
        }
    }
    class MyTimerTask extends TimerTask {
    
        @Override
        public void run() {
            System.out.println("我爱学习");
        }
        
    }

    两个线程间的通信:

    1、什么时候需要通信

    多个线程并发执行时,在默认情况下CPU是随机切换线程的

    如果我们希望他们有规律的执行,就可以使用通信,例如每个线程执行一次打印

    2、怎么通信

    如果希望线程等待,就调用wait()

    如果希望唤醒等待的线程,就调用notify()

    这两个方法必须在同步的代码中执行,并且使用同步锁对象来调用

    import java.util.FormatFlagsConversionMismatchException;
    
    public class Demo4 {
    
        public static void main(String[] args) {
            final Printer p = new Printer();
            
            new Thread(){
                public void run(){
                    while(true){
                        try {
                            p.print1();
                        } catch (InterruptedException e) {
                            
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
            
            new Thread(){
                public void run(){
                    while(true){
                        try {
                            p.print2();
                        } catch (InterruptedException e) {
                            
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
    
    }
    //等待唤醒机制
    class Printer {
        private int flag = 1;
        public void print1() throws InterruptedException {    
            synchronized(this){
                if (flag != 1) {
                    this.wait();                    //当前线程等待
                }
                System.out.print("H");
                System.out.print("e");
                System.out.print("l");
                System.out.print("l");
                System.out.print("o");
                System.out.print("
    ");
                flag = 2;
                this.notify();                        //随机唤醒单个等待的线程            
            }
        }
    
        public void print2() throws InterruptedException {                            
            synchronized (this) {
                if (flag != 2) {
                    this.wait();
                }
                System.out.print("酷");
                System.out.print("狗");
                System.out.print("
    ");
                flag = 1;
                this.notify();
            }
        }
    
    }

    三个或三个以上间的线程通信:

    多个线程通信的问题

      notify()方法是随机唤醒一个线程

      notifyAll()方法是唤醒所有线程

      JDK5之前无法唤醒指定的一个线程

      如果多个线程之间通信,需要使用notifyAll()通知所有线程,用while来反复判断条件

    public class Demo5 {
        public static void main(String[] args) {
            final Printer2 p = new Printer2();
            new Thread() {
                public void run() {
                    while (true) {
                        try {
                            p.print1();
                        } catch (InterruptedException e) {
    
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
    
            new Thread() {
                public void run() {
                    while (true) {
                        try {
                            p.print2();
                        } catch (InterruptedException e) {
    
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
    
            new Thread() {
                public void run() {
                    while (true) {
                        try {
                            p.print3();
                        } catch (InterruptedException e) {
    
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
    }
    
    class Printer2 {
        private int flag = 1;
    
        public void print1() throws InterruptedException {
            synchronized (this) {
                while (flag != 1) {
                    this.wait(); // 当前线程等待
                }
                System.out.print("H");
                System.out.print("e");
                System.out.print("l");
                System.out.print("l");
                System.out.print("o");
                System.out.print("
    ");
                flag = 2;
                // this.notify(); //随机唤醒单个等待的线程
                this.notifyAll();
            }
        }
    
        public void print2() throws InterruptedException {
            synchronized (this) {
                while (flag != 2) {
                    this.wait(); // 线程2在此等待
                }
                System.out.print("酷");
                System.out.print("狗");
                System.out.print("
    ");
                flag = 3;
                // this.notify();
                this.notifyAll();
            }
        }
    
        public void print3() throws InterruptedException {
            synchronized (this) {
                while (flag != 3) {
                    this.wait(); // 线程3在此等待,if语句是在哪里等待,就在哪里起来
                } // while循环是循环判断,每次都会判断标记
                System.out.print("m");
                System.out.print("u");
                System.out.print("s");
                System.out.print("i");
                System.out.print("c");
                System.out.print("
    ");
                flag = 1;
                // this.notify();
                this.notifyAll();
            }
        }
    
    }

    线程间的通信注意的问题:

    1、在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法

    2、为什么wait方法和notify方法定义在Object这类中?

    因为锁对象可以是任意对象,Object是所有的类的基类,所以wait方法和notify方法需要定义在Object这个类中

    3、sleep方法和wait方法的区别?

    a:sleep方法必须传入参数,参数就是时间,时间到了自动醒来

    wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入参数就是直接等待

    b:sleep方法在同步函数或同步代码块中,不释放锁,睡着了也抱着锁睡

    wait方法在同步函数或者同步代码块中,释放锁

    JDK1.5的新特性互斥锁:

    1、同步

    使用ReentrantLock类的lock()和unlock()方法进行同步

    2、通信

    使用ReentrantLock类的newCondition()方法可以获取Condition对象

    需要等待的时候使用Condition的await()方法,唤醒的时候用signal()方法

    不同的线程使用不同的Condition,这样就能区分唤醒的时候找哪个线程了

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Demo6 {
        public static void main(String[] args) {
            Printer3 p = new Printer3();
            
            new Thread(){
                public void run(){
                    while(true){
                        try {
                            p.print1();
                        } catch (InterruptedException e) {
                            
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
            
            new Thread(){
                public void run(){
                    while(true){
                        try {
                            p.print2();
                        } catch (InterruptedException e) {
                            
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
            
            new Thread(){
                public void run(){
                    while(true){
                        try {
                            p.print3();
                        } catch (InterruptedException e) {
                            
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
    }
    class Printer3 {
        private ReentrantLock r = new ReentrantLock();
        private Condition c1 = r.newCondition();
        private Condition c2 = r.newCondition();
        private Condition c3 = r.newCondition();
        
        private int flag = 1;
        public void print1() throws InterruptedException {
            r.lock();                                    //获取锁
                if (flag != 1) {
                    c1.await();
                }
                System.out.print("H");
                System.out.print("e");
                System.out.print("l");
                System.out.print("l");
                System.out.print("o");
                System.out.print("
    ");
                flag = 2;
                // this.notify(); //随机唤醒单个等待的线程
                c2.signal();
                r.unlock();                                //释放锁
            }
        
    
        public void print2() throws InterruptedException {
            r.lock();
                if (flag != 2) {
                    c2.await();
                }
                System.out.print("酷");
                System.out.print("狗");
                System.out.print("
    ");
                flag = 3;
                // this.notify();
                c3.signal();
            r.unlock();
            }
    
        public void print3() throws InterruptedException {
            r.lock();
                if (flag != 3) {
                    c3.await();
                }
                System.out.print("m");
                System.out.print("u");
                System.out.print("s");
                System.out.print("i");
                System.out.print("c");
                System.out.print("
    ");
                flag = 1;
                // this.notify();
                c1.signal();
            r.unlock();
        }
    
    }

    线程的五种状态:

    新建,就绪,运行,阻塞,死亡

    GUI

    如何创建一个窗口并显示:

    Graphical User Interface(图形用户接口)

    package com.gui;
    
    import java.awt.Frame;
    import java.awt.Toolkit;
    
    public class Demo1 {
        public static void main(String[] args) {
            Frame f = new Frame("我的第一个窗口");
            f.setSize(400,600);                        //设置窗体大小        
            f.setLocation(500, 50);                    //设置窗体位置
            f.setIconImage(Toolkit.getDefaultToolkit().createImage("qq.png"));
            
            f.setVisible(true);                        //设置窗体可见
        }
    }

    布局管理器:

    FlowLayout(流式布局管理器)

      从左到右的顺序排列

      Panel默认的布局管理器

    BorderLayout(边界布局管理器)

      东,南,西,北,中

      Frame默认的布局管理器

    GridLayout(网格布局管理器)

      规则的矩阵

    CardLayout(卡片布局管理器)

      选项卡

    GridBahLayout(网格包布局管理器)

      非规则的矩阵

    package com.gui;
    
    import java.awt.Button;
    import java.awt.FlowLayout;
    import java.awt.Frame;
    import java.awt.Toolkit;
    
    public class Demo1 {
        public static void main(String[] args) {
            Frame f = new Frame("我的第一个窗口");
            f.setSize(400,600);                        //设置窗体大小        
            f.setLocation(500, 50);                    //设置窗体位置
            f.setIconImage(Toolkit.getDefaultToolkit().createImage("qq.png"));
            Button b1 = new Button("按钮");
            f.add(b1);
            f.setLayout(new FlowLayout());            //设置布局管理器
            f.setVisible(true);                        //设置窗体可见
        }
    }

    窗体监听:

    package com.gui;
    
    import java.awt.Button;
    import java.awt.FlowLayout;
    import java.awt.Frame;
    import java.awt.Toolkit;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.awt.event.WindowListener;
    
    public class Demo1 {
        public static void main(String[] args) {
            Frame f = new Frame("我的第一个窗口");
            f.setSize(400, 600); // 设置窗体大小
            f.setLocation(500, 50); // 设置窗体位置
            f.setIconImage(Toolkit.getDefaultToolkit().createImage("qq.png"));
            Button b1 = new Button("按钮");
            f.add(b1);
            f.setLayout(new FlowLayout()); // 设置布局管理器
            // f.addWindowListener(new MyWindowAdapter());
            f.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
            f.setVisible(true); // 设置窗体可见
        }
    }

    鼠标监听:

    b1.addMouseListener(new MouseAdapter() {
                /*@Override
                public void mouseClicked(MouseEvent e) {    //单击
                    System.exit(0);
                }*/
                @Override
                public void mouseReleased(MouseEvent e) {    //释放
                    System.exit(0);
                }
            });

    键盘监听和键盘事件:

    b1.addKeyListener(new KeyAdapter() {
                @Override
                public void keyReleased(KeyEvent e) {
                    //System.exit(0);
                    //System.out.println(e.getKeyCode());
                    //if (e.getKeyCode() == 32) {
                    if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                        System.exit(0);
                    }
                        
                }
            });

    动作监听:

    b2.addActionListener(new ActionListener() {            //添加动作监听,应用场景就是暂停视频和播放视频
                @Override
                public void actionPerformed(ActionEvent e) {
                    System.exit(0);
                }
            });

     适配器设计模式:

    a:什么是适配器

    在使用监听器的时候,需要定义一个类事件监听器接口

    通常接口中有多个方法,而程序中不一定所有的都用到,但又必须重写,这很繁琐

    适配器简化了这些操作,我们定义监听器时只要继承适配器,然后重写需要的方法即可

    b:适配器原理

    适配器就是一个类,实现了监听器接口,所有抽象方法都重写了,但是方法全是空的

    适配器类需要定义成抽象的,因为创建该类对象,调用空方法是没有意义的

    目的就是为了简化程序员的操作,定义监听器时继承适配器,只重写需要的方法就可以了

    事件处理:

    事件:用户的一个操作

    事件源:被操作的组件

    监听器:一个自定义类的对象,实现了监听器接口,包含事件处理方法,吧监听器添加在事件源上,

    当事件发生的时候虚拟机就会自动调用监听器中的事件处理方法

      

  • 相关阅读:
    软考之操作系统
    牛腩javascript(二)之正则表达式
    牛腩javascript(一)
    软考之算法
    软考之数据结构
    软考之路之刷屏开始
    XML中的几种比较
    北大青鸟ASP.NET之总结篇
    Webassembly 学习2 -- Js 与C 数据交互
    nginx-proxy_redirect
  • 原文地址:https://www.cnblogs.com/clqbolg/p/10974854.html
Copyright © 2020-2023  润新知