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:适配器原理

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

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

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

事件处理:

事件:用户的一个操作

事件源:被操作的组件

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

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

  

原文地址:https://www.cnblogs.com/clqbolg/p/10974854.html