美文网首页
07-Java基础-多线程 & 单例

07-Java基础-多线程 & 单例

作者: xiaohan_zhang | 来源:发表于2017-07-27 22:11 被阅读0次

多线程、单例

  • 线程
    线程是程序执行的一条路径, 一个进程中可以包含多条线程。
    多线程并发执行可以提高程序的效率, 可以同时完成多项工作。

  • 并行和并发
    并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)
    并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。
    并行:两个或多个事件在同一时刻点发生。
    并发:两个或多个事件在同一时间段内发生。

  • 创建线程
    线程类:Thread类和Thread的子类才能称之为线程。
    方式一:继承Thread类。
    方式二:实现Runnable接口。
    方式三:匿名内部类。(用的最少)

1、方式一

public class ThreadDemo {
    public static void main (String[] args) {
      // 方式一:继承Thread类
      // 4)在main方法中创建线程对象,并启动线程。
        MyThread myThread = new MyThread();
      // 5)开启线程
        myThread.start();  
        myThread.getName();   //获取当前线程
    }
}

// 1)定义一个类A继承于java.long. Thread类。
class MyThread extends Thread{
// 2)在A类中覆盖Thread的run方法。
    @Override
    public void run() {
        super.run();
// 3)在run方法中编写需要执行的代码。
        for (int i = 0; i < 100; i ++){
        Thread.currentThread().setName("线程---2");  // 设置线程名称
        System.out.println(Thread.currentThread());   // 获取当前线程
        }
    }
}

好处:可以直接使用Thread类中的方法,代码简单。
弊端:如果已经有了父类,就不能用这种方法。
2、方式二

public class ThreadDemo {

    public static void main (String[] args) {
      // 方式二:实现Runnable接口
      // 4)在main方法中创建线程对象,并启动线程。
        Thread thread = new Thread(new GameThread());
        thread.start();
    }
}


// 1)定义一个类A实现java.lang.Runnable接口。
class GameThread implements Runnable{
// 2)在A类中实现Runnable接口中的run方法。
    @Override
    public void run() {
// 3)在run方法中编写需要执行的代码。
        for (int i = 0; i < 100; i ++){
            this.setName("线程---1");  // 设置线程名称
            System.out.println(Thread.currentThread());   // 获取当前线程
        }
    }
}

好处:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的。
弊端:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法。

3、匿名内部类创建线程

public class ThreadDemo {
    public static void main (String[] args) {
        //方式三:匿名内部类
        // 1)将Runnable的子类对象传递给Thread的构造方法
        new Thread(new Runnable() {   
        // 2)重写run方法
            @Override
            public void run() {
        // 3)将要执行的代码写在run方法中
                for (int i = 0; i < 100; i ++){
                    Thread.currentThread().setName("线程---3");  // 设置线程名称
                    System.out.println(Thread.currentThread());   //获取当前线程
                }
            }
        }).start();   // 开启线程
    }
}
  • 线程休眠
    让执行的线程暂停一段时间,进入计时等待状态。
    方法:state void sleep(long mills)
    调用sleep后,当前线程放弃CPU,sleep线程不会获得执行机会,此状态下的线程不会释放同步锁。
    该方法更多的用于网络延迟。
new Thread(new Runnable() {
    @Override
    public void run() {
         for (int i = 20; i >= 0; i--){
             System.out.println("倒计时" + i + "秒");
             try {
                 Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
         }
    }
}).start();
  • 守护线程
    在后台运行的线程,其目的是为其它线程提供服务。JVM的垃圾回收线程就是典型的后台线程。
    setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出。

特点:若所有的前台线程都死亡,后台线程自动死亡,前台线程没有结束,后台线程是不会结束的。
thread.isDaemon() 返回是否为后台线程。
前台线程创建的线程默认是前台线程,可以通过setDaemon()方法设置为后台线程(setDaemon()方法必须在start方法前调用)。后台线程创建的线程默认为后台线程。

    private static void daemonDemo(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 2; i++) {
                    System.out.println(Thread.currentThread());
                }
            }
        }).start();


        Thread thread1 = new Thread(){
            @Override
            public void run() {
                super.run();
                for (int i = 0; i < 2; i++) {
                    System.out.println(Thread.currentThread());
                }
            }
        };

        Thread thread = new Thread(){
            @Override
            public void run() {
                super.run();
                for (int i = 0; i < 50; i++) {
                    System.out.println(Thread.currentThread());
                }
            }
        };
        thread.setDaemon(true);
        thread.start();
    }
  • 加入线程
    join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续
    join(int), 可以等待指定线程执行指定毫秒后继续
    private static void joinThreadDemo(){
        final Thread thread =  new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 50; i++) {
                    System.out.println(Thread.currentThread() + "-----111111");
                }
            }
        };

        thread.start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    if (i == 2){
                        try {
//                            thread.join();  // 线程1开始执行,执行完后线程2才开始执行
                            thread.join(1); // 线程1执行1毫米,然后线程1和线程2交替执行
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread() + "-----222222");
                }
            }
        }).start();
    }
  • 礼让线程(了解)
    Thread.yield():表示当前线程对象提示调度器自己愿意让出CPU资源,但是调度器可以自由忽略该意愿。
    调用该方法后,线程进入就绪状态,所以某个线程调用了yield方法之后,调度器又把它调度出来重新执行。
    开发中很少使用该方法,主要用于调试,它可能有助于因多线程调度的竞争条件下的错误重现。

  • 设置线程优先级(了解)
    每个线程都有优先级,优先级的高低只和线程获得执行机会的多少有关,与执行先后顺序无关,执行顺序取决于CPU的调度。

/**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

// 设置优先级(建议三个常量就可以了)
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Thread.currentThread().setPriority(3);
// 获取当前线程优先级
Thread.currentThread().getPriority()

每个线程都有默认优先级,主线程默认优先级是5;
如果A线程创建了B线程,那么B线程与A线程有相同优先级。

作用不是很明显

        Thread thread1 = new Thread(){
            @Override
            public void run() {
                super.run();
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread() + "-----111");
                }
            }
        };
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                super.run();
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread() + "-----222");
                }
            }
        };

        thread1.setPriority(10);
        thread2.setPriority(1);
        thread1.start();
        thread2.start();
    }
  • 线程安全
  • 同步代码块
    当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步。
    如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码。
    使用 synchronized 关键字加上一个锁对象来定义一段代码, 这就叫同步代码块。
    多个同步代码块如果使用相同的锁对象, 那么他们就是同步的。
// 同步代码块
synchronized (this) {
      // 多个线程共享的代码    
}
    private static void test(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    PrinterTest.print1();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    PrinterTest.print2();
                }
            }
        }).start();
    }


class PrinterTest {
    ThreadDemo threadDemo = new ThreadDemo();
    public static void print1() {
        synchronized(threadDemo){               //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
            System.out.print("你");
            System.out.print("是");
            System.out.print("猪");
            System.out.print("吗");
            System.out.print("\r\n");
        }
    }

    public static void print2() {
        synchronized(threadDemo){
            System.out.print("无");
            System.out.print("糖");
            System.out.print("口");
            System.out.print("香");
            System.out.print("糖");
            System.out.print("\r\n");
        }
    }
}
  • 同步方法
    使用synchronized修饰的方法。
    // 同步方法
    synchronized private void doWork () {
        // 多个线程共享的代码
    }
class PrinterTest {
    public static void print1() {
        synchronized(PrinterTest.class){               //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
            System.out.print("你");
            System.out.print("是");
            System.out.print("猪");
            System.out.print("吗");
            System.out.print("\r\n");
        }
    }
    /*
     * 非静态同步函数的锁是:this
     * 静态的同步函数的锁是:字节码对象
     */
    public static synchronized void print2() {
        synchronized(PrinterTest.class){
            System.out.print("无");
            System.out.print("糖");
            System.out.print("口");
            System.out.print("香");
            System.out.print("糖");
            System.out.print("\r\n");
        }
    }
    public synchronized void print3() {
        synchronized(this){
            System.out.print("金");
            System.out.print("钢");
            System.out.print("狼");
            System.out.print("\r\n");
        }
    }
}
  • 死锁
    多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁。

  • 单例
    保证类在内存中只有一个对象。

  • 饿汉式

/** 
 * 单例模式的实现:饿汉式,线程安全 但效率比较低 
 */  
public class SingletonTest {  
    // 定义一个私有的构造方法
    private SingletonTest() {  
    }  
    // 将自身的实例对象设置为一个属性,并加上Static和final修饰符
    private static final SingletonTest instance = new SingletonTest();  
    // 静态方法返回该类的实例
    public static SingletonTest getInstancei() {  
        return instance;  
    }  
}
  • 懒汉式
/**  
 * 单例模式的实现:懒汉式,线程安全
 */  
public class SingletonTest {
    // 定义私有构造方法(防止通过 new SingletonTest()去实例化)
    private SingletonTest() {   
    }   
    // 定义一个SingletonTest类型的变量(不初始化,注意这里没有使用final关键字)
    private static SingletonTest instance;   
    // 定义一个静态的方法(调用时再初始化SingletonTest,使用synchronized 避免多线程访问时,可能造成重的复初始化问题)
    public static synchronized  SingletonTest getInstance() {   
        if (instance == null)   
            instance = new SingletonTest();   
        return instance;   
    }   
} 
  • 静态内部类法
public class Singleton{  
    private static class SingletonHolder{  
        public static Singleton instance = new Singleton();  
    }  
    private Singleton(){
    }  
    public static Singleton getSingleton(){  
        return SingletonHolder.instance;  
    }  
}  
  • 双重检查锁
public class Singleton {
    private static volatile Singleton instance = null;
    private Singleton(){}

    public static Singleton getInstance(){
        if (instance == null){
            synchronized(Singleton.class){
                if (instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  • 枚举法
public enum Singleton {
    INSTACE;
    private String name;
    public String getName() {
    return name;
    }
}
  • Timer
public class TimerDemo {
    public static void main (String[] args) {
        // 3秒后执行
        new Timer().schedule(new MyTimerTask(), 3000);
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("匿名内部类方式");
            }
        },2000);


        // 周期执行
        // 延迟3秒,每1秒执行一次
        new Timer().schedule(new MyTimerTask(), 3000, 1000);
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("每隔1秒定时任务");
            }
        },0,1000);
    }
}


class MyTimerTask extends TimerTask {

    @Override
    public void run() {
        System.out.println("Timer test");
    }
}
  • 线程通信

wait():执行该方法线程对象释放同步锁,JVM把该线程存放到等待池中,等待其他线程唤醒该线程。
notify():执行该方法的线程唤醒在等待池中等待的任一线程,把线程转到锁池中等待。
notifyAll():执行该方法的线程唤醒在等待池中等待的所有线程,把线程转到锁池中等待。

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

public class ThreadCommunicationDemo {
    public static void main(String[] args){
        MyPrinter myPrinter = new MyPrinter();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    myPrinter.print1();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    myPrinter.print2();
                }
            }
        }).start();

        // 三个线程通信
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    myPrinter.print3();
                }
            }
        }).start();
    }
}

class MyPrinter {
    private int flag = 1;
    public void print1() {
        synchronized(this){               //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
            // 两个线程通信
            /*if (flag != 1){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }*/
            while (flag != 1){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.print("你");
            System.out.print("是");
            System.out.print("猪");
            System.out.print("吗");
            System.out.print("\r\n");
            flag = 2;
            // 两个线程通信
//            this.notify();  // 随机唤醒单个线程

            // 三个线程通信
            this.notifyAll();
        }
    }

    public synchronized void print2() {
        synchronized(this){
            /*if (flag != 2){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }*/
            while (flag != 2){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.print("无");
            System.out.print("糖");
            System.out.print("口");
            System.out.print("香");
            System.out.print("糖");
            System.out.print("\r\n");
            // 两个线程通信
//            flag = 1;
//            this.notify();
            // 三个线程通信
            flag = 3;
            this.notifyAll();
        }
    }

    public synchronized void print3() {
        synchronized(this){
            while (flag != 3){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.print("金");
            System.out.print("钢");
            System.out.print("狼");
            System.out.print("\r\n");
            flag = 1;
            this.notifyAll();
        }
    }
}

如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件。
注意事项:
1.在同步代码块中用哪个对象锁,就用哪个对象调用wait 方法。
2.sleep方法必须传入参数,参数就是时间,时间到了自动醒来,
wait 方法可以传入参数也可以不传入参数。
3.sleep方法在同步函数或同步代码块中,不释放锁;
wait 方法在同步函数或同步代码块中,释放锁。

  • 互斥锁
    1)使用Lock机制取代synchronized代码块和synchronized方法。
    2)使用Condition接口对象的await()和signalAll()方法等待和唤醒线程。
    1.同步
    使用ReentrantLock类的lock()和unlock()方法进行同步
    2.通信
    使用ReentrantLock 类的 newCondition() 方法可以获取Condition对象;
    需要等待的时候使用 Condition的 await() 方法, 唤醒的时候用 signal() 方法;
    不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了;
public class ReentrantLockDemo {
    public static void main(String[] args) {
        final MyPrinter1 myPrinter = new MyPrinter1();

        new Thread() {
            public void run() {
                while(true) {
                    myPrinter.print1();
                }
            }
        }.start();

        new Thread() {
            public void run() {
                while(true) {
                    myPrinter.print2();
                }
            }
        }.start();

        new Thread() {
            public void run() {
                while(true) {
                    myPrinter.print3();
                }
            }
        }.start();
    }

}

class MyPrinter1 {
    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() {
        r.lock();   // 获取锁
        if(flag != 1) {
            try {
                c1.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print("你");
        System.out.print("是");
        System.out.print("猪");
        System.out.print("吗");
        System.out.print("\r\n");
        flag = 2;
        c2.signal();
        r.unlock();     // 释放锁
    }

    public void print2() {
        r.lock();
        if(flag != 2) {
            try {
                c2.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print("金");
        System.out.print("钢");
        System.out.print("狼");
        System.out.print("\r\n");
        flag = 3;
        c3.signal();
        r.unlock();
    }

    public void print3() {
        r.lock();
        if(flag != 3) {
            try {
                c3.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print("无");
        System.out.print("糖");
        System.out.print("口");
        System.out.print("香");
        System.out.print("糖");
        System.out.print("\r\n");
        flag = 1;
        c1.signal();
        r.unlock();
    }
}
  • 线程组(了解)
    Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
    默认情况下,所有的线程都属于主线程组。

public final ThreadGroup getThreadGroup() // 通过线程对象获取它所属于的组
public final String getName() // 通过线程组对象获取他组的名字

也可以给线程设置分组
1.ThreadGroup(String name) 创建线程组对象并给其赋值名字
2.创建线程对象
3.Thread(ThreadGroup?group, Runnable?target, String?name)
4.设置整组的优先级或者守护线程

public class ThreadGroupDemo {
    public static void main(String[] args) {
        threadGroup();
        myThreadGroup();
    }

    public static void threadGroup() {
        MyRunnable mr = new MyRunnable();
        Thread t1 = new Thread(mr, "张三");
        Thread t2 = new Thread(mr, "李四");
        // 获取线程组
        ThreadGroup tg1 = t1.getThreadGroup();
        ThreadGroup tg2 = t2.getThreadGroup();

        String name1 = tg1.getName();
        String name2 = tg2.getName();
        System.out.println(name1);
        System.out.println(name2);
        // 线程默认情况下属于main线程组
        // 默任情况下,所有的线程都属于同一个组
        System.out.println(Thread.currentThread().getThreadGroup().getName());
    }

    public static void myThreadGroup(){
        ThreadGroup tg = new ThreadGroup("我是一个新的线程组");      //创建新的线程组
        MyRunnable mr = new MyRunnable();                               //创建Runnable的子类对象

        Thread t1 = new Thread(tg, mr, "张三");                   //将线程t1放在组中
        Thread t2 = new Thread(tg, mr, "李四");                   //将线程t2放在组中

        System.out.println(t1.getThreadGroup().getName());              //获取组名
        System.out.println(t2.getThreadGroup().getName());

        // 通过组名称设置后台线程,表示该组的线程都是后台线程
        tg.setDaemon(true);
    }
}

class MyRunnable implements Runnable {

    @Override
    public void run() {
        for(int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName() + "...." + i);
        }
    }
}
  • 线程的生命周期
    线程的生命周期

1、新建状态(new)
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

2、就绪状态(ready)
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

3、运行状态(running)
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

4、阻塞状态(blocked)
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
阻塞状态只能先进入就绪状态,不能直接进入运行状态。

5、死亡状态(terminated)
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

  • 线程池(了解)
    程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
/*JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。
*/
ExecutorService pool = Executors.newFixedThreadPool(2);
// 可以执行Runnable对象或者Callable对象代表的线程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());

//结束线程池
pool.shutdown();
  • 工厂模式
    工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
    客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性。
// 动物抽象类
public abstract class Animal {
    public abstract void eat();
}
// 工厂接口
public interface Factory {
    public Animal createAnimal();
}
// 具体狗类
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
// 具体猫类
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
// 狗工厂
public class DogFactory implements Factory {
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}
// 猫工厂
public class CatFactory implements Factory {
    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}
// 使用
public class Test {
    public static void main(String[] args) {
        DogFactory df = new DogFactory();
        Dog d = (Dog) df.createAnimal();
        d.eat();
    }
}

相关文章

  • 07-Java基础-多线程 & 单例

    多线程、单例 线程线程是程序执行的一条路径, 一个进程中可以包含多条线程。多线程并发执行可以提高程序的效率, 可以...

  • 单例模式

    单例模式介绍 把单例模式放到多线程基础这块,是因为单例和多线程有一点的关系。何为单例模式? 在它的核心结构中只包含...

  • swift单例

    普通版单例 多线程版单例

  • Java多线程--并行模式与算法

    Java多线程--并行模式与算法 单例模式 虽然单例模式和并行没有直接关系,但是我们经常会在多线程中使用到单例。单...

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • Swift多线程:GCD进阶,单例、信号量、任务组

    Swift多线程:GCD进阶,单例、信号量、任务组 Swift多线程:GCD进阶,单例、信号量、任务组

  • OC和Swift单例的写法

    一 、OC中单例的写法:1.普通单例的写法 2. 利用多线程来写单例 #pragma mark --- 普通单例写...

  • Unity3d游戏开发之-单例设计模式-多线程一

    单例模式3:多线程一

  • 多线程(下)&GUI

    day25(多线程(下)&GUI) 1_多线程(单例设计模式)(掌握) 单例设计模式:保证类在内存中只有一个对象。...

  • 关于JAVA栈与堆的讨论

    今天晚上收获颇丰详细讨论了java的一些知识 引入点是 单例多线程 多例单线程 单例多线程: SpringMV...

网友评论

      本文标题:07-Java基础-多线程 & 单例

      本文链接:https://www.haomeiwen.com/subject/wflkkxtx.html