多线程初阶

目录

 一,线程,进程,程序。

一,概念

二,进程与线程区别:

三,创建线程的四种方式

一,继承Thread类,覆写run方法

二,实现Runable接口,覆写run方法。

1,继承Thread类和实现Runnable接口的区别:

2,lambda表达式实现创建线程写法

3,匿名内部类实现写法

4,Runnable与匿名内部类创建线程写法

四,实现Callable接口,覆写call方法

五,使用线程池

六,多线程与顺序执行的速度差

四,线程的属性

五,线程的常用方法

一,run()方法

 二,start()方法,线程的启动方法。

JDK与JRE的区别:

start()方法和run()方法区别:

 三,线程中断方法——线程之间通信

1,通过共享变量进行中断

 2,通过   thread.interrupt();  中断线程

 线程内置中断的两种方法

三,线程的等待方法;

1,join():在那个线程中调用join方法就会网当前线程等待,直到其他线程执行结束。

2,wait();

3,sleep();

4,yield()

5,notify()  & wait()

 六,线程的状态

 一,线程新建运行和终止状态。

 二,三种阻塞状态

 七,线程安全

 一,JMM:java内存模型(不是JVM内存区域模型),描述线程的工作内存和主内存的关系。

二,线程安全必须同时保证以下三个特性 

三,synchronized(同步)关键字——对象锁

synchronized特性:1,互斥性   2,强制刷新内存  3,可重入。

 volatile 关键字:可见性,内存屏障

八,线程的等待与唤醒机制(wait(),notify()),但是必须搭配synchronized锁来执行。

九,单例模式

单例模式:保证某个类在程序中,有且只有一个对象。

单例模式的设计:

懒汉式单例:在需要这个对象时,才会产生对象,此时的线程时不安全的

饿汉式单例:在类的初始化的时候创建对象,在类初始化的时候,就会创建对象,线程安全

解决懒汉式单例模式的线程安全问题

 JDK中的阻塞队列

生产消费者模型:

 定时器:Timer类,设定一个时间,以及一个相应的任务,在指定时间后执行某个任务。

核心方法:


 一,线程,进程,程序。

一,概念

程序:一系列有组织的文件,操作系统实现封装API,实现不同的效果

进程:程序的一次执行过程,进程是操作系统资源分配的最小单位。

线程:进程中的子任务(QQ和两个不同的聊天就是QQ进程中的两个子线程)

一个进程至少包含一个主线程,存在多个不同的子线程,多个线程共享操作系统分配给进程的资源,线程是操作系统调度的最小单位。

如何定位主机上的一个进程:

        不同的程序拥有不同的端口号,操作系统通过不同的端口号,来定位进程,给进程分配资源。进程的端口号是不会变化的,但是进程的PCB(进程的信息)是变化的。

二,进程与线程区别:

1,进程是OS资源分配的基本单位,线程是OS调度的基本单位。

2,创建和销毁一个进程,远比创建和销毁一个线程慢的多,线程是轻量级的。

3,调度一个线程也比调度一个进程快得多。

4,一个进程至少包含一个主线程,可以包含多个线程

5,不同进程之间相互独立,不会共享资源,同一个进程的线程之间的共享进程的资源。

三,创建线程的四种方式

一,继承Thread类,覆写run方法

继承Thread类是创建一个线程对象。

public class ExtendThread  extends Thread{
    @Override
    public void run() {
            System.out.println("子线程");
            System.out.println("子线程");
            System.out.println("子线程");
            System.out.println("子线程");
    }
}
class MyThread {
    public static void main(String[] args) {
        ExtendThread t1 = new ExtendThread();
        t1.start();
        System.out.println("主线程的方法");
    }
}

二,实现Runable接口,覆写run方法。

实现Runnable接口是创建一个子线程的任务。实现Runnable接口更加灵活,还可以继承其他类和实现其他接口,使用继承就不能狗继承其他类。

public class ImplRunable implements Runnable{
    @Override
    public void run() {
        System.out.println("子线程");
    }
}
class Main{
    public static void main(String[] args) {
        Thread thread = new Thread(new ImplRunable());
        thread.start();
        System.out.println("主线程.....");
    }
}

1,继承Thread类和实现Runnable接口的区别:

区别:继承Thread类直接产生的线程对象,而实现这个接口只是创建了一个线程任务,在需要启动这个线程任务时,直接将线程任务对象传给Thread类,就可以将启动该任务。

共同:最终线程启动都是调用线程start()方法,才能启动。

2,lambda表达式实现创建线程写法

public class ThreadBy {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("线程1");
        },"线程1");
        thread.start();
        System.out.println("主线程");
    }
}

3,匿名内部类实现写法

Thread thread1 = new Thread(){
            @Override
            public void run() {
                System.out.println("匿名内部类");
            }
        };
        thread1.start();

4,Runnable与匿名内部类创建线程写法

Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable与匿名内部类实现创建线程");
            }
        },"匿名,Runnbale");
        thread2.start()

四,实现Callable接口,覆写call方法

五,使用线程池

多线程进阶上,线程池及锁的介绍http://t.csdn.cn/BS7dd

六,多线程与顺序执行的速度差

public class MoreThreadSpeed {
    static long x = 0;
    static long y = 0;
    public static void main(String[] args) throws InterruptedException {
        fun();
        fun1();
    }
    public static void fun() throws InterruptedException {
        Thread t1 = new Thread(() ->{
            for (int i = 0; i < 5000_0000_0; i++) {
                x++;
            }
        });
        for (int i = 0; i < 5000_0000_0; i++) {
            x++;
        }
        long start = System.currentTimeMillis();
        t1.start();
        t1.join();
        long end = System.currentTimeMillis();
        System.out.println(end - start + " " +x);
    }
    public static void fun1(){
        long start = System.currentTimeMillis();
        for (int i = 0;i < 1000_0000_00;i++){
            y++;
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start + " " +y);
    }
}

四,线程的属性

1,ID 获取ID的方法:getID();     //  ID是线程的唯一表示PID,不同线程的ID不会重复

2,名称    获取方法:getName(); // 名称各种调试工具用到

3,状态    获取方法 : getState();   // 线程处在运行态还是阻塞态 等等。

4,优先级    获取方法: getPriority(); //优先级越高,越先被调度,最低是1,最高为10,普通线程一般为5。

5,是否后台线程   获取方法: isDaemon();  // 后台线程,jvm会在最后一个后台线程结束以后关闭

6,是否存活    获取方法:isAlive(); // run方法是否运行结束

7,是否被中断   获取方法:isInterrupted(); // 线程是否被中断运行

public class ThreadAttr {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() ->{
            for (int i = 0; i < 2; i++) {
                System.out.println("线程ID" + Thread.currentThread().getId());
                System.out.println("线程名" +Thread.currentThread().getName());
                System.out.println("线程优先级"+Thread.currentThread().getPriority());
                System.out.println("线程状体"+Thread.currentThread().getState());
                System.out.println("后台线程 ? "+Thread.currentThread().isDaemon());
                System.out.println("存活 ?"+Thread.currentThread().isAlive());
                System.out.println("被中断 ?" +Thread.currentThread().isInterrupted());
                try {
                    Thread.sleep(1000);
                    System.out.println("___________________________________");
                    System.out.println("睡眠线程状态"+Thread.currentThread().getState());
                    System.out.println("睡眠和后台线程 ? "+Thread.currentThread().isDaemon());
                    System.out.println("睡眠和存活 ?"+Thread.currentThread().isAlive());
                    System.out.println("睡眠后被中断 ?" +Thread.currentThread().isInterrupted());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        thread.join();
        System.out.println("___________________________________");
        System.out.println("线程ID" + Thread.currentThread().getId());
        System.out.println("线程名" +Thread.currentThread().getName());
        System.out.println("线程优先级"+Thread.currentThread().getPriority());
        System.out.println("线程状体"+Thread.currentThread().getState());
        System.out.println("后台线程 ? "+Thread.currentThread().isDaemon());
        System.out.println("存活 ?"+Thread.currentThread().isAlive());
        System.out.println("被中断 ?" +Thread.currentThread().isInterrupted());
    }
}

五,线程的常用方法

Thread类的方法,在那个线程中调用,就在那个线程生效。

一,run()方法

package 多线程.复习;

import java.util.Random;

public class ThreadDemo1 {
    private static class MyThread extends Thread{
        @Override
        public void run() {
            Random random = new Random();
            while (true){
                System.out.println(Thread.currentThread().getName());
                try {
                    sleep(random.nextInt(10));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
        Random random = new Random();
        while (true){
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(random.nextInt(10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程类的run方法:run方法是线程的核心方法,,在java.lang.Thread包中,线程中所有要做的事都在run方法中。

启动线程调用start()方法,线程启动以后,JVM会自动调用各个线程的run方法,多个线程之间是并行运行。

 

 二,start()方法,线程的启动方法。

JDK与JRE的区别:

1,JRE:java运行时环境,面向java程序的使用者,在一台计算机上安装了jre,就可以运行java程序,jre包括了JVM和java核心类库。

2,JDK:面向开发人员,JDK中包括了,两个jre,java核心类库,java开发工具和开发工具包,jre中在JDK下的JRE目录时Java运行环境的jre,另一个时java开发环境下的jre。

jconsle:查看当前JVM内部的线程情况。有JDK提供的开发工具。

start()方法和run()方法区别:

start()方法:启动线程,将线程从创建态改变为就绪态,当时间片轮到该线程时,jvm就会自动调用线程run方法,进入运行态,在run方法执行结束以后就会进入终止态。多个线程启动start()方法,多个线程并发执行。

run():线程的普通方法,如果一个线程没有启动,而直接调用run方法,那么执行的就不是该线程,而是主线程,不调用start方法,而直接调用run方法,多个线程会顺序执行,并不能达到线程并发的效果,

如果在线程1还没有执行结束的时候,再次调用线程1的start方法,就回报线程状态异常的错误。

 三,线程中断方法——线程之间通信

中断线程:在线程还在运行是,剥夺线程的资源,就会中断线程。

1,通过共享变量进行中断

public class ThreadInterruptrd {
    private static  class MyThread implements Runnable{
        boolean isRupt = false;//通过共享这一个变量,来控制线程的中断
        @Override
        public void run() {
            while (!isRupt){
                System.out.println("正在通话中。。。。。");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("抢线了,糟糕,电话挂掉了");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread();
        Thread thread = new Thread(t1,"子线程");
        thread.start();
        System.out.println("主线程信号良好。。。");
        Thread.sleep(2000);
        t1.isRupt = true;
        System.out.println("主线程信号太差了。。。");
    }
}

 2,通过   thread.interrupt();  中断线程

//通过内置的属性中断线程
public class ThreadInterrupted {
    private static class MyRunnable implements Runnable{
        @Override
        public void run() {
            while (true){
                System.out.println("渣渣正在通话中。。。");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.err.println("那个狗日剪我电话线");
                    break;
                }
            }
            System.out.println("渣渣被迫挂了电话。。。。");
        }
    }

    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable,"渣渣");
        thread.start();
        System.out.println("主线程安全");
        Thread.sleep(2000);
//        System.out.println("警报!!!有人在剪电话线。。");
        thread.interrupt();
        System.out.println("电话线断了。。。");
    }
}

 线程内置中断的两种方法

a,当线程调用sleep/wait/join方法时等方法处在阻塞状态,收到中断通知thread.isinterruptrd,就会抛出一个InterruptedException异常,当抛出后,当前线程的中断状态就会被清除。

也就是说当中断异常产生以后,会向外抛出异常,线程的状态会从中断状态还原成运行状态。

 

b,判断线程是否被中断

interrupted()(就像一个会回弹的开关),isInterRupted()方法(就像一个不会回弹的开关)。

interrupted线程的静态方法,判断线程是否被中断:Thread.interrupted(),清楚中断标志

isInterrupted线程的实例方法,判断线程是否被中断。thread.isInterrupted()不会清楚中断标志。

三,线程的等待方法;

1,join():在那个线程中调用join方法就会网当前线程等待,直到其他线程执行结束。

在主方法中调用子线程的join,阻塞的是主线程,直到子线程执行结束,才会执行后面的代码。

public class JoinOfThread {
    private static class JoinMethod implements Runnable{
        int num = 0;
        @Override
        public void run() {
            for (int i = 0; i < 3; i++) {
                System.out.println("子线程占用资源");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new JoinMethod(),"子线程");
        thread.start();
        thread.join();//在主线程中调用子线程的join方法,就会让主线程进入阻塞状态,直到子线程执行结束,才会开始主线程
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程占用资源");
            Thread.sleep(1000);
        }
    }
}

 

2,wait();

3,sleep();

4,yield()

5,notify()  & wait()

package 多线程.复习.线程方法;

import 多线程.复习.线程安全.SynchronizedKey;

public class NotifyAndWait {
    private static class ThreadOfOB{
        static Object lock = new Object();
    }

    public static void main(String[] args) {
        ThreadOfOB ob = new ThreadOfOB();
        Thread t1 = new Thread(()->{
            synchronized(ob.lock) {
                try {
                    System.out.println(Thread.currentThread().getName()+"线程进入等待状态");
                    ob.lock.wait();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName()+"线程被唤醒");
                ob.lock.notify();
            }
        });
        Thread t2 = new Thread(() ->{
            synchronized(ob.lock) {
                try {
                    System.out.println(Thread.currentThread().getName()+"线程进入等待状态");
                    ob.lock.wait();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName()+"线程被唤醒");

            }
        });
        Thread t3 = new Thread(() ->{
            synchronized(ob.lock) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName()+"准备唤醒锁");
                ob.lock.notify();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName()+"唤醒了lock锁");
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }
}

 六,线程的状态

public class StateThread {
    public static void main(String[] args) {
        for (Thread.State state : Thread.State.values()) {
            System.out.println(state);
        }
    }
}

 

 

 一,线程新建运行和终止状态。

isAlive:除了 new 和 terminated 都是存活状态

 

 二,三种阻塞状态

public class WaitState {
    public static void main(String[] args) {
        Object lock = new Object();
        Thread t1 = new Thread(() ->{
            synchronized (lock){
                while (true){
                    try {
//                        Thread.sleep(1000);//调用此方法,线程1处在超时等待状态:timed-waiting
                        lock.wait();//调用wait,线程1进入wait状态,等待其他线程唤醒
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        },"t1");
        Thread t2 = new Thread(() ->{
            synchronized (lock){
                System.out.println("她");
            }
        },"t2");
        t1.start();
        t2.start();
    }
}

waiting:通过Object类的wait方法,将线程置入等待状态,需要通过OBject类的notify唤醒

blocked:锁等待,需要获取锁,才能进入运行态

timed-wating:超时等待状态。超时自动唤醒线程

 

 七,线程安全

线程串行执行和并行执行结果一致,那么就是线程不安全的。

    static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() ->{
            for (int i = 0; i < 5000; i++) {
                count++;
            }
        });
        Thread t2 = new Thread(() ->{
            for (int i = 0; i < 5000; i++) {
                count++;
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
    

 

 

 一,JMM:java内存模型(不是JVM内存区域模型),描述线程的工作内存和主内存的关系。

描述java在多线程的场景下,java的线程内存和主内存的关系。

每个线程在工作时,都会从主内存中读取共享变量(不是线程的内部变量),关于共享变量的操作都是在工作内存中,工作内存执行完毕后,写回主内存。

二,线程安全必须同时保证以下三个特性 

 1,原子性

该操作不会被中断,要么全部执行,要不都不执行,不存在中间操作。

例如:a = 10 为原子操作,将10直接赋给a;

a ++ 为非原子操作;读a,运算a+1, a = a +1;分三步走。

2,可见性

一个线程堆一个共享变量的修改,其他线程可见,这种特性为可见性。

3,防止指令重排

cpu对指令执行的顺序进行调整。

要保证安全,就必须保证原子性,可见性和防止指令重排

三,synchronized(同步)关键字——对象锁

synchronized保证原子性和可见性。

锁:在java内部每个对象都有一块内存(临界区),描述当前对象 "锁"的信息,锁的信息就表示当前对象被那个线程所持有。

若锁信息没有保存线程,就表示当前对象被那个线程锁持有

若锁信息保存了线程id,其他线程要获取锁,就会处在阻塞状态。(等待队列不是FIFO的算法)

synchronized特性:1,互斥性   2,强制刷新内存  3,可重入。

互斥性:多个线程访问同一个资源,一次只允许一个线程对对资源进行加锁,其他线程进入阻塞状态。

强制刷新内存:可见性和原子性保证了,在读写操作未完成之前,临界区资源只能被当前线程访问,当前线程读写完毕,会强制刷新主存临界区资源的值。

可重入:获取到临界的资源以后,可以再次对临界区内的资源进行加锁。

private static class Count{
        int count = 0;
        synchronized void increased(){
            count++;
        }
        synchronized void increased1(){
            //当进入increased1方法,需要再次进入increased方法,如果不支持可重入,就会线程就会一致再次等待,就会死锁
            increased();
        }
    }

synchronized是个对象锁,必须要有集体的对象让他锁:

1,synchronized修饰成员方法,则锁的就是调用该方法的对象。

        synchronized  void increased2(){
            while (true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName());
            }
        }
    }

    public static void main(String[] args) {
        Count c1 = new Count();
        Count c2 = new Count();
        Count c3 = new Count();
        Thread t1 = new Thread(() -> {
            c1.increased2();
        },"t1");
        Thread t2 = new Thread(() -> {
            c2.increased2();
        },"t2");
        Thread t3 = new Thread(() -> {
            c3.increased2();
        },"t3");
        t1.start();
        t2.start();
        t3.start();
    }

修饰成员方法,只会锁当前对象。三个线程不是同一个对象调用的,因此三个线程轮流访问该成员方法。 

2,synchronized修饰静态方法,则锁的就是全局为一的通过反射获得到的类名.class对象

synchronized static void increased2(){
            while (true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName());
            }
        }
    }

    public static void main(String[] args) {
        Count c1 = new Count();
        Count c2 = new Count();
        Count c3 = new Count();
        Thread t1 = new Thread(() -> {
            c1.increased2();
        },"t1");
        Thread t2 = new Thread(() -> {
            c2.increased2();
        },"t2");
        Thread t3 = new Thread(() -> {
            c3.increased2();
        },"t3");
        t1.start();
        t2.start();
        t3.start();
    }

 修饰静态方法,锁的是全局唯一的class对象,因此,线程1最先获取到该对象,因此线程1一直持有锁,才会一直打印线程1。无论通过那个count对象,只有一个对象能方法。

 

 Java的并发工具包:java.util.concurrent

 volatile 关键字:可见性,内存屏障

使用volatile关键字保证可见性,不能保证原子性

1,线程每次访问volatile关键字,无论该线程中是否已经读取该变量,都会到主内存中再次读取该变量。

public class NonVolatile {
    private static  class Count{
        int count = 0;
    }

    public static void main(String[] args) {
        Count count = new Count();
        Thread t1 = new Thread(() -> {
            while (count.count == 0){
                
            }
            System.out.println(count.count + ":退出循环");
        },"t1");
        t1.start();
        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(1000);
//                    count.count++;
                Scanner sc = new Scanner(System.in);
                System.out.println("count = ");
                count.count = sc.nextInt();
                System.out.println("t2的JJM中的count值为:"+count.count);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        },"t2");
        t2.start();
    }
}

2,线程写volatile关键字时,该线程立即将写完之后的变量强制刷新到内存,其他线程访问会一直等待,知道该线程写操作结束。

使用volatile关键字修饰变量,相当于一个内存屏障

 

八,线程的等待与唤醒机制(wait(),notify()),但是必须搭配synchronized锁来执行。

九,单例模式

单例模式:保证某个类在程序中,有且只有一个对象。

单例模式的设计:

懒汉式单例:在需要这个对象时,才会产生对象,此时的线程时不安全的

1,私有化构造方法,

public class 单例模式 {
    private 单例模式(){}//私有化构造方法。
}

2,在本类中自己创建私有的静态的一个对象(设置为静态的原因是因为,成员对象只能通过对象来调用,而构造方法在外部不可见,无法创建对象来获取该私有对象这个属性,因此采用静态的修饰,在类加载的时候创建对象。)

public class 单例模式 {
    private static 单例模式 single;
    private 单例模式(){}//私有化构造方法。
}

3,类加载阶段创建着唯一的对象。

public class 单例模式 {//懒汉
    private static 单例模式 single;
    private 单例模式(){}//私有化构造方法。
    public static 单例模式 getObject(){
        single = new 单例模式();//在需要这个对象才创建对象
        return single;//通过这个方法来返回这个唯一的对象
    }
}

饿汉式单例:在类的初始化的时候创建对象,在类初始化的时候,就会创建对象,线程安全

1,私有化构造方法和创建属性

public class 单例模式 {
    private static 单例模式 single = new 单例模式();
    private 单例模式(){}//私有化构造方法。
}

2,并返回对象。

public class 单例模式 {
    private static 单例模式 single = new 单例模式();
    private 单例模式(){}//私有化构造方法。
    public static 单例模式 getObject(){
        return single;//通过这个方法来返回这个唯一的对象
    }
}

解决懒汉式单例模式的线程安全问题

直接对方法加synchronized,这种方法锁的粒度太粗,如果存在其他的加锁方法,就不会并发。

class LizeTon{
    private static LizeTon lizeTon ;
    private LizeTon(){}
    //直接在获取对象的方法上加synchronized关键字,来保证原子性和可见性。
    private static synchronized LizeTon getLizeTon(){
        if (lizeTon == null){
            lizeTon = new LizeTon();
        }
        return lizeTon;
    }
}

在方法里面加锁

class LizeTon{
    private static LizeTon lizeTon ;
    private LizeTon(){}
    //直接在获取对象的方法上加synchronized关键字,来保证原子性和可见性。
    private static LizeTon getLizeTon(){
        if (lizeTon == null){//多个线程可以同时进入该方法,
            synchronized (LizeTon.class){//在这里会阻塞多个线程
                if(lizeTon == null){//一个线程执行结束后,其他线程进来再次读lizeTon,保证不会重复创建对象
                    lizeTon = new LizeTon();
                }
            }
        }
        return lizeTon;
    }
}

双重枷锁:

使用volatile关键字,保证实例化不会中断。禁止指令重排

 JDK中的阻塞队列

BlockingQueue:put入,take出

生产消费者模型:


import java.util.Random;
import java.util.concurrent.*;

public class 生产消费者 {

    public static void main(String[] args) {
        BlockingQueue blockingDeque = new LinkedBlockingQueue(2);
        Thread t1 = new Thread(() -> {
            while (true){
                try {
                    int val = (int) blockingDeque.take();
                    System.out.println("消费者消费:" + val);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"消费者");
        Random random = new Random();
        Thread t2 =new Thread(() -> {
            while (true){
                try {
                    int val = random.nextInt(100);
                    System.out.println("生产者生产:" + val);
                    blockingDeque.put(val);//在次设置为墙,防止指令重排
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }
        },"生产者");
        t1.start();
        t2.start();
    }
}

 

 定时器:Timer类,设定一个时间,以及一个相应的任务,在指定时间后执行某个任务。

核心方法:

schedule方法:

public class 定时器Timer {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("3S后打印");
            }
        },3000);
    }
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值