Java 复习整理day09
阅读原文时间:2023年07月11日阅读:3

package com.it.demo01_thread;

/*
案例: 多线程简介.

概述:  
    指的是进程有多条执行路径, 统称叫: 多线程.

    进程: 指的是可执行程序, 文件(例如: .exe)  
        大白话翻译: 车.  
    线程: 指的就是 进程的 执行路径(或者叫: 执行单元)  
        大白话翻译: 车道.

面试题: 多线程并行和多线程并发的区别是什么?  
    多线程并行:  
        指的是两个(或以上)的线程同时执行.  前提: 需要多核CPU.  
    多线程并发:  
         指的是两个(或以上)的线程请求执行, 但是同一瞬间CPU只能执行一个线程,  
         于是就安排它们交替执行, 因为时间间隔非常短, 我们看起来好像是同时执行的, 其实不是.

案例: 演示单线程程序, 即: 前边的代码没有执行完毕前, 后边的代码不会执行.  

*/
public class Demo01 {
public static void main(String[] args) {
for (int i = 0; i < 200; i++) {
System.out.println("run,……. " + i);
}

    for (int i = 0; i < 200; i++) {  
        System.out.println("main... " + i);  
    }  
}  

}

package com.it.demo01_thread;

/*
案例: 演示多线程的实现方式一: 继承Thread类.

在Java程序中, 线程的顶级类是: Thread, 即: 所有的线程类都是Thread类的子类.

多线程的方式如下:  
    方式一: 继承Thread类.  
        步骤:  
            1. 自定义一个线程类(MyThread), 让它继承Thread类.  
            2. 重写Thread#run()  
            3. 把要执行的代码放到 run()方法中.  
            4. 在main方法中创建线程类对象.  
            5. 开启线程.  
    方式二: 实现Runnable接口.

    方式三: 实现Callable接口, 必须和线程池相结合使用.

细节:  
    1. 开启线程调用的是 Thread#start()方法, 如果调用run()方法, 只是普通的方法调用而已.  
    2. 同一线程不能重复开启, 否则会报: IllegalThreadStateException异常.  
    3. 多线程的执行具有 随机性 和 延迟性.  
    4. 一台电脑上可以有多个进程, 这些进程之间的数据是相互隔离的.  
    5. 一个进程可以有多条线程, 这些线程可以共享该进程的数据.  

*/
public class Demo02 {
public static void main(String[] args) {
//4. 在main方法中创建线程类对象.
MyThread mt = new MyThread();
//5. 开启线程
//mt.run(); //只是普通的方法调用.
mt.start();
//mt.start(); //同一线程不能重复开启

    //main线程的内容, 输出200次 main...  
    for (int i = 0; i < 200; i++) {  
        System.out.println("main... " + i);  
    }  
}  

}

package com.it.demo01_thread;

/*
案例: 演示多线程的实现方式二: 实现Runnable接口.

多线程的方式如下:  
    方式一: 继承Thread类.

    方式二: 实现Runnable接口.  
         步骤:  
            1. 自定义一个资源类(MyRunnable), 让它实现Runnable接口.  
            2. 重写Runnable#run()  
            3. 把要执行的代码放到 run()方法中.  
            4. 在main方法中创建资源类对象, 然后将其作为参数传入Thread类的构造, 从而创建线程对象.  
            5. 开启线程.

    方式三: 实现Callable接口.

细节:  
    1. 开启线程调用的是 Thread#start()方法, 如果调用run()方法, 只是普通的方法调用而已.  
    2. 同一线程不能重复开启, 否则会报: IllegalThreadStateException异常.  
    3. 多线程的执行具有 随机性 和 延迟性.  
    4. 一台电脑上可以有多个进程, 这些进程之间的数据是相互隔离的.  
    5. 一个进程可以有多条线程, 这些线程可以共享该进程的数据.  

*/
public class Demo03 {
public static void main(String[] args) {
//4. 在main方法中创建资源类对象, 然后将其作为参数传入Thread类的构造, 从而创建线程对象.
//4.1 创建资源类对象
MyRunnable mr = new MyRunnable();
//4.2 将其作为参数传入Thread类的构造, 从而创建线程对象.
Thread th = new Thread(mr);

    //5. 开启线程.  
    th.start();

    for (int i = 0; i < 200; i++) {  
        System.out.println("main... " + i);  
    }  
}  

}

package com.it.demo01_thread;

/*
案例: 演示Thread类的构造方法和成员方法

涉及到的Thread类中的成员:  
    构造方法:  
        public Thread():                    分配一个新的线程对象。  
        public Thread(String name)          分配一个指定名字的新的线程对象。

        public Thread(Runnable target)      分配一个带有指定目标新的线程对象。  
        public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。  
    常用方法:  
        public String getName():                获取当前线程名称。  
        public void start():                    导致此线程开始执行; Java虚拟机调用此线程的run方法。  
        public void run():                      此线程要执行的任务在此处定义代码。  
        public static void sleep(long millis):  使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。  
        public static Thread currentThread():   返回对当前正在执行的线程对象的引用。  

*/
public class Demo04 {
public static void main(String[] args) {
//需求: 创建两个线程对象, 并开启.
//方式一: 继承Thread类.
//method01();

    //方式二: 实现Runnable接口.  
    MyRunnable mr = new MyRunnable();  
    Thread t1 = new Thread(mr);  
    t1.setName("乔峰");

    Thread t2 = new Thread(mr, "虚竹");

    t1.start();  
    t2.start();

}

public static void method01() {  
    MyThread mt1 = new MyThread();  
    mt1.setName("刘亦菲");

    MyThread mt2 = new MyThread("赵丽颖");

    mt1.start();  
    mt2.start();  
}  

}

package com.it.demo01_thread;

/*
案例: 通过匿名内部类的方式实现多线程.

*/
public class Demo05 {
public static void main(String[] args) {
//方式一: 继承Thread类.
new Thread() {
//重写run方法, 把要执行的写到方法中
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("匿名内部类, 继承Thread类版 " + i);
}
}
}.start();

    //方式二: 实现Runnable接口.  
    //格式: new Thread(Runnable接口的子类对象).start();  
    new Thread(new Runnable() {  
        @Override  
        public void run() {  
            for (int i = 0; i < 100; i++) {  
                System.out.println("匿名内部类,  实现Runnable接口.... " + i);  
            }  
        }  
    }).start();

    //扩展: 因为Runnable接口中只有一个抽象方法, 所以可以尝试通过Lambda表达式实现.  
    new Thread(() -> {  
        for (int i = 0; i < 100; i++) {  
            System.out.println("Lambda表达式,  实现Runnable接口 " + i);  
        }  
    }).start();

}  

}

package com.it.demo01_thread;

//1. 自定义一个线程类(MyThread), 让它继承Thread类.
public class MyThread extends Thread{
//细节: 如果要给线程起名字, 记得写构造方法
public MyThread() {
}

public MyThread(String name) {  
    super(name);  
}

//2. 重写Thread#run()  
@Override  
public void run() {  
    //3. 把要执行的代码放到 run()方法中.  
    for (int i = 0; i < 200; i++) {  
        System.out.println(this.getName() + "  run,....... " + i);  
    };  
}  

}

package com.it.demo01_thread;

//资源类

//1. 自定义一个资源类(MyRunnable), 让它实现Runnable接口.
public class MyRunnable implements Runnable{

//2. 重写Runnable#run()  
@Override  
public void run() {  
    //3. 把要执行的代码放到 run()方法中.  
    for (int i = 0; i < 200; i++) {  
        System.out.println(Thread.currentThread().getName() + "  run,....... " + i);  
    }  
}  

}

package com.it.demo02_tickets;

//自定义的线程类, 用来模拟卖票
public class MyThread extends Thread{
//1. 定义变量, 记录票数.
private static int tickets = 66; //细节1: 4个窗口共享100张票

//2. 定义构造方法.  
public MyThread() {  
}

public MyThread(String name) {  
    super(name);  
}

//3. 重写run()方法, 里边写是具体的卖票的逻辑.  
@Override  
public void run() {  
    //具体的卖票的逻辑.  
    while(true) {  
        //做越界处理, 没票就不卖了.  
        if (tickets <= 0) {  
            break;  
        }

        //加入休眠线程, 让程序出现非法值的概率大一些.  
        try {  
            Thread.sleep(50);       //单位是毫秒         线程1, 线程2, 线程3, 线程4  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }

        //具体的卖票  
        System.out.println(getName() + " 正在售出第 "+ tickets-- +" 张票");  
    }

    /\*  
        多线程模拟卖票, 会出现非法值的问题:  
            出现负数:  
                核心点: 1. if判断  2. sleep(), 在哪睡, 就在哪醒.  
                具体流程:  
                    1. 当tickets的值为1的时候, 如果此时4个线程分别都抢到了资源, 那么它们都会处于休眠的状态, 此时, 不管哪个线程醒来, 它们执行流程如下:  
                    2. 假设线程1先醒来, 会打印: 窗口1正在买第 1 张票, 之后tickets--, 即: tickets = 0  
                    3. 假设线程2 醒来, 会打印: 窗口2正在买第 0 张票, 之后tickets--, 即: tickets = -1  
                    4. 假设线程3 醒来, 会打印: 窗口3正在买第 -1 张票, 之后tickets--, 即: tickets = -2  
                    5. 假设线程4 醒来, 会打印: 窗口4正在买第 -2 张票, 之后tickets--, 即: tickets = -3

            出现重复值:  
                核心点: tickets-- , 这行代码相当于: tickets = tickets - 1;  这行代码做了 3 件事儿:  
                    1. 读值.  tickets = 66  
                    2. 改值.  tickets - 1  = 66 - 1 = 65  
                    3. 赋值.  tickets = 65  
                 此时, 当该线程(窗口)打印完售票动作, 还没来得及修改tickets的值之前, 被别的线程抢走了CPU资源,  
                 就会出现重复值的问题.  
     \*/  
}  

}

package com.it.demo02_tickets;

/*
案例: 模拟卖票, 4个窗口卖100张票.
*/
public class Demo01 {
public static void main(String[] args) {
//1. 创建4个线程.
MyThread mt1 = new MyThread("窗口1");
MyThread mt2 = new MyThread("窗口2");
MyThread mt3 = new MyThread("窗口3");
MyThread mt4 = new MyThread("窗口4");

    //2. 开启线程, 卖票.  
    mt1.start();  
    mt2.start();  
    mt3.start();  
    mt4.start();  
}  

}

package com.it.demo03_tickets;

//自定义的线程类, 用来模拟卖票
public class MyThread extends Thread {
//1. 定义变量, 记录票数.
private static int tickets = 100; //细节1: 4个窗口共享100张票

//2. 定义构造方法.  
public MyThread() {  
}

public MyThread(String name) {  
    super(name);  
}

//3. 重写run()方法, 里边写是具体的卖票的逻辑.  
@Override  
public void run() {  
    //具体的卖票的逻辑.  
    while (true) {  
        //一次卖票逻辑  
        synchronized (MyThread.class) {  //锁对象一般会写: 该类的字节码文件  
        //synchronized (this) {  //锁对象一般会写: 该类的字节码文件, 锁不住.  
            //做越界处理, 没票就不卖了.  
            if (tickets <= 0) {  
                break;  
            }

            //加入休眠线程, 让程序出现非法值的概率大一些.  
            try {  
                Thread.sleep(50);       //单位是毫秒         线程1, 线程2, 线程3, 线程4  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }

            //具体的卖票  
            System.out.println(getName() + " 正在售出第 " + tickets-- + " 张票");  
        }  
    }

}  

}

package com.it.demo03_tickets;

/*
案例: 模拟卖票, 4个窗口卖100张票, 解决非法值问题.

解决方案: 采用同步代码块解决  
   格式:  
        synchronized(锁对象) {  
            //这里写的是要加锁的代码.  
        }  
   注意事项:  
        1. 同步代码块的锁对象可以是 任意类型的对象.  
        2. 必须使用同一把锁, 否则可能出现锁不住的情况.  
结论:  
    线程安全(同步), 效率低,  线程不安全(不同步), 效率高.  

*/
public class Demo01 {
public static void main(String[] args) {
//1. 创建4个线程.
MyThread mt1 = new MyThread("窗口1");
MyThread mt2 = new MyThread("窗口2");
MyThread mt3 = new MyThread("窗口3");
MyThread mt4 = new MyThread("窗口4");

    //2. 开启线程, 卖票.  
    mt1.start();  
    mt2.start();  
    mt3.start();  
    mt4.start();  
}  

}

package com.it.demo04_tickets_runnable;

import com.it.demo03_tickets.MyThread;

//自定义的资源类, 用来模拟卖票.
public class MyRunnable implements Runnable {
//1. 定义变量, 记录票数.
private int tickets = 100;

//2. 我们不用定义构造方法, 用系统默认的就行.

//3. 重写run()方法, 里边写是具体的卖票的逻辑.  
@Override  
public void run() {  
    //具体的卖票的逻辑.  
    while (true) {  
        //一次卖票逻辑  
        //synchronized (MyRunnable.class) {   //可以  
        synchronized (this) {                 //可以  
            if (tickets <= 0) {  
                break;  
            }

            //加入休眠线程, 让程序出现非法值的概率大一些.  
            try {  
                Thread.sleep(50);       //单位是毫秒         线程1, 线程2, 线程3, 线程4  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }

            //具体的卖票  
            System.out.println(Thread.currentThread().getName() + " 正在售出第 " + tickets-- + " 张票");  
        }  
    }  
}  

}

package com.it.demo04_tickets_runnable;

/*
案例: 多线程模拟卖票, 实现Runnable接口版.

实现Runnable接口 和 继承Thread版的 卖票代码相比, 以下4个地方可以优化:  
    1. 定义票数的变量, 可以用不写 static, 因为资源对象就一个.  
    2. 构造方法无需定义, 用系统默认提供的 无参构造即可.  
    3. 锁对象可以是this, 因为资源对象就一个.  
    4. 因为MyRunnable类和Thread类之间无关系, 所以不能直接调用 Thread#getName();

线程同步简介:  
    概述:  
        多线程 并发 操作同一数据, 就有可能引发安全问题, 需要用到同步解决.  
    特点:  
        线程同步(安全), 效率低,  线程不同步(不安全), 效率高.  
    分类:  
        同步代码块:  
            格式:  
                synchronized(锁对象) {  
                    //这里写的是要加锁的代码.  
                }  
           注意事项:  
                1. 同步代码块的锁对象可以是 任意类型的对象.  
                2. 必须使用同一把锁, 否则可能出现锁不住的情况.  
        同步方法:  
            说明: 就是在方法的声明上, 加上 synchronized 关键字.  
                静态同步方法:   锁对象是 该类的字节码文件对象, 即: 类名.class  
                非静态同步方法: 锁对象是 this  

*/
public class Demo01 {
public static void main(String[] args) {
//1. 创建资源类对象.
MyRunnable mr = new MyRunnable();
//2. 创建线程对象.
Thread th1 = new Thread(mr, "窗口1");
Thread th2 = new Thread(mr, "窗口2");
Thread th3 = new Thread(mr, "窗口3");
Thread th4 = new Thread(mr, "窗口4");
//3. 开启线程.
th1.start();
th2.start();
th3.start();
th4.start();
}

public synchronized void show1() {      //非静态同步方法, 锁对象: this  
    System.out.println(1);  
    System.out.println(2);  
    System.out.println(3);  
    System.out.println(4);  
    System.out.println(5);  
}

public synchronized static void show2() {    //静态同步方法, 锁对象: 该类的字节码文件

}  

}

package com.it.demo05_deadlock;

import com.sun.scenario.effect.LockableResource;

import java.util.concurrent.locks.Lock;

/*
案例: 演示死锁的代码(只在面试用)

大白话翻译:  
    死锁指的是同步代码块的嵌套, 实际开发中, 我们在写代码的时候, 也要尽量规避这个问题.

原理分析:  
    1. 死锁需要两个线程, 两把锁.  
    2. 一个线程先抢锁A, 后抢锁B, 另一个线程先抢锁B, 后抢锁A.  
    3. 这个时候就有可能发生死锁的现象, 为了让效果更明显, 我们用while(true)改进.  

*/
public class DeadLock {
//1. 定义两把锁.
private static final String LOCKA = "锁A";
private static final String LOCKB = "锁B";

public static void main(String\[\] args) {  
    //2. 创建两个线程对象.  
    //第一个线程对象  
    new Thread("关羽") {  
        @Override  
        public void run() {  
            //为了让效果更明显, 我们用while(true)改进.  
            while (true) {  
                //一个线程先抢锁A, 后抢锁B,  
                synchronized (LOCKA) {  
                    System.out.println(getName() + " 获取到 " + LOCKA + ", 等待 " + LOCKB);  
                    synchronized (LOCKB) {  
                        System.out.println(getName() + " 获取到 " + LOCKB + ", 成功进到小黑屋");  
                    }  
                }  
            }  
        }  
    }.start();

    //第二个线程对象  
    new Thread("张飞") {  
        @Override  
        public void run() {  
            //为了让效果更明显, 我们用while(true)改进.  
            while (true) {  
                // 另一个线程先抢锁B, 后抢锁A.  
                synchronized (LOCKB) {  
                    System.out.println(getName() + " 获取到 " + LOCKB + ", 等待 " + LOCKA);  
                    synchronized (LOCKA) {  
                        System.out.println(getName() + " 获取到 " + LOCKA + ", 成功进到小黑屋");  
                    }  
                }  
            }  
        }  
    }.start();

}  

}
package com.it.demo05_deadlock;

import java.util.Scanner;

/*
案例: 演示IO流阻塞问题.
*/
public class Demo01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请录入您的账号: ");
String username = sc.nextLine();
System.out.println(username);
}
}

package com.it.demo06_priority;

//自定义的线程类
public class MyThread extends Thread{
//构造方法
public MyThread() {
}

public MyThread(String name) {  
    super(name);  
}

@Override  
public void run() {  
    for (int i = 0; i < 10; i++) {  
        System.out.println(getName() + " ... " + i);  
    }  
}  

}

package com.it.demo06_priority;

/*
案例: 演示多线程的优先级问题.

涉及到的Thread类中的成员:  
    成员常量:  
        MAX\_PRIORITY        10  
        MIN\_PRIORITY        1  
        NORM\_PRIORITY       5  
    成员方法:  
        public int getPriority();           获取当前线程的优先级.  
        public void setPriority(int num);   设置当前线程的优先级.

细节:  
    1. 默认优先级为: 5, 范围是1-10.  
    2. 线程的优先级越高, 只是说明该线程 抢到CPU资源的概率会更大, 并不代表它一定第一个执行.

*/
public class Demo01 {
public static void main(String[] args) {
//1. 创建3个线程对象.
MyThread mt1 = new MyThread("飞机 .");
MyThread mt2 = new MyThread("游艇 ..");
MyThread mt3 = new MyThread("高铁 … ");

    //2. 打印上述三个线程的默认优先级.  
   /\* System.out.println(mt1.getPriority());      //默认是: 5  
    System.out.println(mt2.getPriority());  
    System.out.println(mt3.getPriority());\*/

   //3. 查看线程的优先级有哪些  
    /\*System.out.println(Thread.MAX\_PRIORITY);        //10  
    System.out.println(Thread.MIN\_PRIORITY);        //1  
    System.out.println(Thread.NORM\_PRIORITY);      //5\*/

    //4. 设置mt2线程的优先级为10  
    //mt2.setPriority(Thread.MAX\_PRIORITY);  
    mt2.setPriority(10);

    //2. 开启线程  
    mt1.start();  
    mt2.start();  
    mt3.start();  
}  

}

package com.it.demo06_priority;

//自定义的线程类
public class MyThread extends Thread{
//构造方法
public MyThread() {
}

public MyThread(String name) {  
    super(name);  
}

@Override  
public void run() {  
    for (int i = 0; i < 10; i++) {  
        System.out.println(getName() + " ... " + i);  
    }  
}  

}

package com.it.demo06_priority;

/*
案例: 演示多线程的优先级问题.

涉及到的Thread类中的成员:  
    成员常量:  
        MAX\_PRIORITY        10  
        MIN\_PRIORITY        1  
        NORM\_PRIORITY       5  
    成员方法:  
        public int getPriority();           获取当前线程的优先级.  
        public void setPriority(int num);   设置当前线程的优先级.

细节:  
    1. 默认优先级为: 5, 范围是1-10.  
    2. 线程的优先级越高, 只是说明该线程 抢到CPU资源的概率会更大, 并不代表它一定第一个执行.

*/
public class Demo01 {
public static void main(String[] args) {
//1. 创建3个线程对象.
MyThread mt1 = new MyThread("飞机 .");
MyThread mt2 = new MyThread("游艇 ..");
MyThread mt3 = new MyThread("高铁 … ");

    //2. 打印上述三个线程的默认优先级.  
   /\* System.out.println(mt1.getPriority());      //默认是: 5  
    System.out.println(mt2.getPriority());  
    System.out.println(mt3.getPriority());\*/

   //3. 查看线程的优先级有哪些  
    /\*System.out.println(Thread.MAX\_PRIORITY);        //10  
    System.out.println(Thread.MIN\_PRIORITY);        //1  
    System.out.println(Thread.NORM\_PRIORITY);      //5\*/

    //4. 设置mt2线程的优先级为10  
    //mt2.setPriority(Thread.MAX\_PRIORITY);  
    mt2.setPriority(10);

    //2. 开启线程  
    mt1.start();  
    mt2.start();  
    mt3.start();  
}  

}

package com.it.demo07_join;

//自定义的线程类
public class MyThread extends Thread{
//构造方法
public MyThread() {
}

public MyThread(String name) {  
    super(name);  
}

@Override  
public void run() {  
    for (int i = 0; i < 10; i++) {  
        System.out.println(getName() + " ... " + i);  
    }  
}  

}

package com.it.demo07_join;

/*
案例: 演示 加入线程(相当于: 插队)

涉及到的Thread类中的成员:  
   public void join();      //等待这个线程死亡, 其实相当于插队, 只有这个线程执行完毕, 其他线程才会执行.  

*/
public class Demo01 {
public static void main(String[] args) {
//1. 创建3个线程对象.
MyThread mt1 = new MyThread("康熙");
MyThread mt2 = new MyThread("四阿哥");
MyThread mt3 = new MyThread("八阿哥");

    //2. 开启线程  
    mt1.start();  
    //设置mt1为: 加入线程, 即: 让它优先执行.  
    try {  
        mt1.join();  
    } catch (InterruptedException e) {  
        e.printStackTrace();  
    }

    mt2.start();  
    mt3.start();

}  

}

package com.it.demo08_daemon;

//自定义的线程类
public class MyThread extends Thread{
//构造方法
public MyThread() {
}

public MyThread(String name) {  
    super(name);  
}

@Override  
public void run() {  
    for (int i = 0; i < 100; i++) {  
        System.out.println(getName() + " ... " + i);  
    }  
}  

}

package com.it.demo08_daemon;

/*
案例: 演示 守护线程.

涉及到的Thread类中的成员:  
   public void setDaemon(boolean flag);      //传入true: 表示设置当前线程为守护线程.

细节:  
    1. 线程默认都是非守护线程.  
    2. 当非守护线程执行结束后, 所有与其关联的守护线程都会立马结束.  
        //注意: 稍微会有一点点的延迟性.  

*/
public class Demo01 {
public static void main(String[] args) {
//1. 创建3个线程对象.
MyThread mt1 = new MyThread("关羽");
MyThread mt2 = new MyThread("张飞");

    //2. 设置上述的两个线程为: 守护线程.  
    mt1.setDaemon(true);  
    mt2.setDaemon(true);

    //3. 给当前线程(Main主线程)起个别名  
    Thread.currentThread().setName("刘备");

    //4. 开启线程  
    mt1.start();  
    mt2.start();

    //5. 给主线程分配任务.  
    for (int i = 0; i < 10; i++) {  
        System.out.println(Thread.currentThread().getName() + "..." + i);  
    }

}  

}

package com.it.demo09_lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//自定义的线程类, 用来模拟卖票
public class MyThread extends Thread {
//1. 定义变量, 记录票数.
private static int tickets = 100; //细节1: 4个窗口共享100张票

//定义一个Lock锁, 多态  
//Lock锁升级版知识点:  多线程的等待唤醒机制问题, 即: 让线程有规律的执行.  
static Lock lock = new ReentrantLock();     //必须保证同一把锁, 否则可能锁不住.

//2. 定义构造方法.  
public MyThread() {  
}

public MyThread(String name) {  
    super(name);  
}

//3. 重写run()方法, 里边写是具体的卖票的逻辑.  
@Override  
public void run() {  
    //具体的卖票的逻辑.  
    while (true) {  
        //一次卖票逻辑  
        //synchronized (MyThread.class) {  //锁对象一般会写: 该类的字节码文件  
        lock.lock();            //加锁  
        //做越界处理, 没票就不卖了.  
        if (tickets <= 0) {  
            break;  
        }

        //加入休眠线程, 让程序出现非法值的概率大一些.  
        try {  
            Thread.sleep(50);       //单位是毫秒         线程1, 线程2, 线程3, 线程4  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }

        //具体的卖票  
        System.out.println(getName() + " 正在售出第 " + tickets-- + " 张票");  
        lock.unlock();          //解锁  
    }

}  

}

package com.it.demo09_lock;

/*
案例: 演示Lock锁

Lock锁简介:  
    概述:  
        它是JDK1.5的特性, 也是一个接口, 表示互斥锁, 可以让我们实现精准的加锁和解锁的事情.  
    成员方法:  
        unlock();   解锁  
        lock();     加锁

*/
public class Demo01 {
public static void main(String[] args) {
//1. 创建4个线程.
MyThread mt1 = new MyThread("窗口1");
MyThread mt2 = new MyThread("窗口2");
MyThread mt3 = new MyThread("窗口3");
MyThread mt4 = new MyThread("窗口4");

    //2. 开启线程, 卖票.  
    mt1.start();  
    mt2.start();  
    mt3.start();  
    mt4.start();  
}  

}

package com.it.demo10_executor;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/*
案例: 线程池入门.

线程池简介:  
    概述:  
        实际开发中, 当我们需要使用到大量生命周期短的线程对象时, 频繁的创建和销毁线程对象是非常消耗 系统资源的, 针对于这种情况,  
        我们可以搞一个池子出来, 池子里边放一些线程对象, 用的时候去池子拿, 用完之后再返回去, 这个池子就叫: 线程池. 这样做的好处是,  
        节约资源, 提高效率.  
    成员方法:  
        Executors 线程池工具类中的成员方法:  
          public static ExecutorService newFixedThreadPool(int nThreads);   创建线程池对象,nThreads: 表示该池子中有几个线程对象.  
       ExecutorService 它才是具体的 线程池类  
         public Future<?> submit(Runnable task)     提交线程执行任务,这是实现多线程的第二种方式  
         public Future<?> submit(Callable call)     提交线程执行任务,这是实现多线程的第三种方式  
         public void shutdown()                     关闭线程池, 实际开发中, 正常情况下线程池是不关的.  
      Future: 封装的是线程任务执行结束后, 具体的返回值.  
        public V get();     获取线程任务执行结束后, 具体的返回值.  

*/
public class Demo01 {
public static void main(String[] args) throws Exception {
//1. 创建线程池对象, 指定线程对象的个数.
ExecutorService service = Executors.newFixedThreadPool(5);
//2. 给线程池提交任务.
Future future = service.submit(new Runnable() {
@Override
public void run() {
System.out.println("1. 我们只要把任务提交给线程池即可, 需要使用线程对象的时候, 它(线程池)会自动帮我们分配");
System.out.println("2. 具体的任务可以写在: Runnable#run()方法中");
System.out.println("3. 当线程对象使用完毕后, 线程池会自动回收它到线程池中.");
}
});

    //3. 获取线程任务执行结束后的结果.  
    System.out.println(future.get());           //null

    //4. 关闭线程池. 实际开发中, 正常情况下线程池是不关的.  
    service.shutdown();  
}  

}

package com.it.demo10_executor;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/*
案例: 线程池入门.

线程池简介:  
    概述:  
        实际开发中, 当我们需要使用到大量生命周期短的线程对象时, 频繁的创建和销毁线程对象是非常消耗 系统资源的, 针对于这种情况,  
        我们可以搞一个池子出来, 池子里边放一些线程对象, 用的时候去池子拿, 用完之后再返回去, 这个池子就叫: 线程池. 这样做的好处是,  
        节约资源, 提高效率.  
    成员方法:  
        Executors 线程池工具类中的成员方法:  
          public static ExecutorService newFixedThreadPool(int nThreads);   创建线程池对象,nThreads: 表示该池子中有几个线程对象.  
       ExecutorService 它才是具体的 线程池类  
         public Future<?> submit(Runnable task)     提交线程执行任务,这是实现多线程的第二种方式  
         public Future<?> submit(Callable call)     提交线程执行任务,这是实现多线程的第三种方式  
         public void shutdown()                     关闭线程池, 实际开发中, 正常情况下线程池是不关的.  
      Future: 封装的是线程任务执行结束后, 具体的返回值.  
        public V get();     获取线程任务执行结束后, 具体的返回值.

 Runnable接口和Callable接口的区别:  
    1. 作用范围不同.  
        Runnable可以不结合线程池, 直接单独使用.  
        Callable必须结合线程池相结合使用.  
    2. 接口中的方法不同.  
        Runnable#run(), 有异常只能try, 且该方法没有返回值.  
        Callable#call(), 可以throws抛出异常, 且该方法可以有返回值.  

*/
public class Demo02 {
public static void main(String[] args) throws Exception {
//1. 创建线程池对象, 指定线程对象的个数.
ExecutorService service = Executors.newFixedThreadPool(5);
//2. 给线程池提交任务.
//Future future = service.submit(可以是Runnable接口的子类对象);
//Future future = service.submit(也可以是Callable接口的子类对象);
Future future = service.submit(new MyCallable());

    //3. 获取线程任务执行结束后的结果.  
    System.out.println(future.get());           //风和日丽, 晴空万里

    //4. 关闭线程池. 实际开发中, 正常情况下线程池是不关的.  
    service.shutdown();  
}  

}

package com.it.demo10_executor;

import java.util.concurrent.Callable;

//自定义的资源类, 实现Callable接口
public class MyCallable implements Callable {

@Override  
public String call() throws Exception {  
    System.out.println("我是Callable接口封装的 具体任务");  
    return "风和日丽, 晴空万里";  
}  

}

package com.it.demo11_signature;

//定义共享数据区, 奶箱
public class Box {
//定义变量, 记录当前是第几瓶奶
private int milk;

//定义变量, 记录奶箱的状态  
boolean flag = false;       //true: 有奶, false: 无奶

//定义方法, 放奶  
public synchronized void put(int milk) {  
    //判断奶箱是否有牛奶  
    if (flag) {  
        //有牛奶, 就等待  
        try {  
            this.wait();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }

    //具体的放牛奶的逻辑.  
    this.milk = milk;  
    System.out.println("送奶工正在放入第 "+ milk +" 瓶奶");

    //修改奶箱状态.  
    flag = true;  
    //唤醒消费者, 取奶.  
    this.notify();  
}

//定义方法, 取奶.  
public synchronized void get() {  
    //判断奶箱是否有奶  
    if (!flag) {  
        //无奶就等待  
        try {  
            this.wait();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }

    //具体取奶的动作  
    System.out.println("消费者正在获取第 " + milk + " 瓶奶");

    //修改奶箱状态.  
    flag = false;  
    //唤醒生产者, 放奶.  
    this.notify();  
}  

}

package com.it.demo11_signature;

import java.util.Properties;

/*
案例: 演示消费者设计模式.

需求:  
    奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储牛奶和获取牛奶的操作  
    生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作  
    消费者类(Customer):实现Runnable接口,重写run()方法,调用获取牛奶的操作  
    测试类(BoxDemo):里面有main方法,main方法中的代码步骤如下  
    ①创建奶箱对象,这是共享数据区域  
    ②创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作  
    ③创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作  
    ④创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递  
    ⑤启动线程

设计模式简介:  
    概述:  
        设计模式不属于任何语言, 他也不是语法, 而是前辈们总结的用来解决问题的思路和方案, 它是一套用来解决一系列问题的技术方案.  
    分类: 一共23种  
        创建型:  需要创建对象, 5种  
            单例设计模式,  
            工厂方法设计模式  
        结构型:  用来描述类与类之间的关系的 7种  
            装饰设计模式,  
                BufferedReader br = new BufferedReader(new FileReader("1.txt));  
            适配器设计模式  
        行为型:  指的是事物能够做什么        11种  
            模板方法设计模式  
            消费者设计模式  
    推荐一本:  
        大话设计模式(Java版)  

*/
public class BoxTest {
public static void main(String[] args) {
//①创建奶箱对象,这是共享数据区域
Box b = new Box();
//②创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
Producer p = new Producer(b);
//③创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作
Customer c = new Customer(b);
//④创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
Thread th1 = new Thread(p); //负责放牛奶的 生产者
Thread th2 = new Thread(c); //负责获取牛奶的 消费者
//⑤启动线程
th1.start();
th2.start();
}
}

package com.it.demo11_signature;

//定义消费者类, 实现Runnable接口, 充当资源类
public class Customer implements Runnable{
//获取奶箱的引用
private Box box;

//创建消费者对象的时候, 必须指定 奶箱.  
public Customer(Box box) {  
    this.box = box;  
}

@Override  
public void run() {  
    //取牛奶的动作  
    while (true)  
        box.get();  
}  

}

package com.it.demo11_signature;

//定义生产者类, 实现Runnable接口, 充当资源类
public class Producer implements Runnable{
//获取奶箱的引用
private Box box;

//创建生产者对象的时候, 必须指定 奶箱.  
public Producer(Box box) {  
    this.box = box;  
}

@Override  
public void run() {  
    //具体放牛奶的动作  
    for (int i = 1; i <= 10; i++) {  
        box.put(i);  
    }  
}  

}

package cn.it.demo;
/*
* 定义子类,继承Thread
* 重写方法run
*/
public class SubThread extends Thread{
public void run(){
for(int i = 0; i < 50;i++){
System.out.println("run…"+i);
}
}
}

package cn.it.demo;
/*
* 程序中的主线程
*/
public class Demo {
public static void main(String[] args) {
System.out.println(0/0);
function();
System.out.println(Math.abs(-9));
}

public static void function(){  
    for(int i = 0 ; i < 10000;i++){  
        System.out.println(i);  
    }  
}  

}

package cn.it.demo;
/*
* 创建和启动一个线程
* 创建Thread子类对象
* 子类对象调用方法start()
* 让线程程序执行,JVM调用线程中的run
*/
public class ThreadDemo {
public static void main(String[] args) {
SubThread st = new SubThread();
SubThread st1 = new SubThread();
st.start();
st1.start();
for(int i = 0; i < 50;i++){
System.out.println("main…"+i);
}
}
}

package cn.it.demo1;
/*
* 获取线程名字,父类Thread方法
* String getName()
*/
public class NameThread extends Thread{

public NameThread(){  
    super("小强");  
}

public void run(){  
    System.out.println(getName());  
}  

}
package cn.it.demo1;
/*
* 每个线程,都有自己的名字
* 运行方法main线程,名字就是"main"
* 其他新键的线程也有名字,默认 "Thread-0","Thread-1"
*
* JVM开启主线程,运行方法main,主线程也是线程,是线程必然就是
* Thread类对象
* Thread类中,静态方法
* static Thread currentThread()返回正在执行的线程对象
*/
public class ThreadDemo {
public static void main(String[] args) {
NameThread nt = new NameThread();
nt.setName("旺财");
nt.start();

    /\*Thread t =Thread.currentThread();  
    System.out.println(t.getName());\*/  
    System.out.println(Thread.currentThread().getName());

}  

}

package cn.it.demo2;

public class SleepThread extends Thread{
public void run(){
for(int i = 0 ; i < 5 ;i++){
try{
Thread.sleep(500);
}catch(Exception ex){

        }  
        System.out.println(i);  
    }  
}  

}

package cn.it.demo2;

public class ThreadDemo {
public static void main(String[] args) throws Exception{
/*for(int i = 0 ; i < 5 ;i++){
Thread.sleep(50);
System.out.println(i);
}*/

    new SleepThread().start();  
}  

}

package cn.it.demo3;
/*
* 实现线程成功的另一个方式,接口实现
* 实现接口Runnable,重写run方法
*/
public class SubRunnable implements Runnable{
public void run(){
for(int i = 0 ; i < 50; i++){
System.out.println("run…"+i);
}
}
}

package cn.it.demo3;
/*
* 实现接口方式的线程
* 创建Thread类对象,构造方法中,传递Runnable接口实现类
* 调用Thread类方法start()
*/
public class ThreadDemo {
public static void main(String[] args) {
SubRunnable sr = new SubRunnable();
Thread t = new Thread(sr);
t.start();
for(int i = 0 ; i < 50; i++){
System.out.println("main…"+i);
}
}
}

package cn.it.demo4;
/*
* 使用匿名内部类,实现多线程程序
* 前提: 继承或者接口实现
* new 父类或者接口(){
* 重写抽象方法
* }
*/
public class ThreadDemo {
public static void main(String[] args) {
//继承方式 XXX extends Thread{ public void run(){}}
new Thread(){
public void run(){
System.out.println("!!!");
}
}.start();

    //实现接口方式  XXX implements Runnable{ public void run(){}}

    Runnable r = new Runnable(){  
        public void run(){  
            System.out.println("###");  
        }  
    };  
    new Thread(r).start();

    new Thread(new Runnable(){  
        public void run(){  
            System.out.println("@@@");  
        }  
    }).start();

}  

}

package cn.it.demo5;
/*
* Callable 接口的实现类,作为线程提交任务出现
* 使用方法返回值
*/

import java.util.concurrent.Callable;

public class ThreadPoolCallable implements Callable{
public String call(){
return "abc";
}
}

package cn.it.demo5;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*
* JDK1.5新特性,实现线程池程序
* 使用工厂类 Executors中的静态方法创建线程对象,指定线程的个数
* static ExecutorService newFixedThreadPool(int 个数) 返回线程池对象
* 返回的是ExecutorService接口的实现类 (线程池对象)
*
* 接口实现类对象,调用方法submit (Ruunable r) 提交线程执行任务
*
*/
public class ThreadPoolDemo {
public static void main(String[] args) {
//调用工厂类的静态方法,创建线程池对象
//返回线程池对象,是返回的接口
ExecutorService es = Executors.newFixedThreadPool(2);
//调用接口实现类对象es中的方法submit提交线程任务
//将Runnable接口实现类对象,传递
es.submit(new ThreadPoolRunnable());
es.submit(new ThreadPoolRunnable());
es.submit(new ThreadPoolRunnable());

}  

}

package cn.it.demo5;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/*
* 实现线程程序的第三个方式,实现Callable接口方式
* 实现步骤
* 工厂类 Executors静态方法newFixedThreadPool方法,创建线程池对象
* 线程池对象ExecutorService接口实现类,调用方法submit提交线程任务
* submit(Callable c)
*/
public class ThreadPoolDemo1 {
public static void main(String[] args)throws Exception {
ExecutorService es = Executors.newFixedThreadPool(2);
//提交线程任务的方法submit方法返回 Future接口的实现类
Future f = es.submit(new ThreadPoolCallable());
String s = f.get();
System.out.println(s);
}
}

package cn.it.demo5;

public class ThreadPoolRunnable implements Runnable {
public void run(){
System.out.println(Thread.currentThread().getName()+" 线程提交任务");
}
}

package cn.it.demo6;

import java.util.concurrent.Callable;

public class GetSumCallable implements Callable{
private int a;
public GetSumCallable(int a){
this.a=a;
}

public Integer call(){  
    int sum = 0 ;  
    for(int i = 1 ; i <=a ; i++){  
        sum = sum + i ;  
    }  
    return sum;  
}  

}

package cn.it.demo6;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/*
* 使用多线程技术,求和
* 两个线程,1个线程计算1+100,另一个线程计算1+200的和
* 多线程的异步计算
*/
public class ThreadPoolDemo {
public static void main(String[] args)throws Exception {
ExecutorService es = Executors.newFixedThreadPool(2);
Future f1 =es.submit(new GetSumCallable(100));
Future f2 =es.submit(new GetSumCallable(200));
System.out.println(f1.get());
System.out.println(f2.get());
es.shutdown();
}
}

package cn.it.demo;
/*
* 多线程并发访问同一个数据资源
* 3个线程,对一个票资源,出售
*/
public class ThreadDemo {
public static void main(String[] args) {
//创建Runnable接口实现类对象
Tickets t = new Tickets();
//创建3个Thread类对象,传递Runnable接口实现类
Thread t0 = new Thread(t);
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);

    t0.start();t1.start();t2.start();

}  

}

package cn.it.demo;
/*
* 通过线程休眠,出现安全问题
* 解决安全问题,Java程序,提供技术,同步技术
* 公式:
* synchronized(任意对象){
* 线程要操作的共享数据
* }
* 同步代码块
*/
public class Tickets implements Runnable{

//定义出售的票源  
private int ticket = 100;  
private Object obj = new Object();

public void run(){  
    while(true){  
        //线程共享数据,保证安全,加入同步代码块  
        synchronized(obj){  
        //对票数判断,大于0,可以出售,变量--操作  
            if( ticket > 0){  
                try{  
                   Thread.sleep(10);  
                }catch(Exception ex){}  
                System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);  
            }  
        }  
    }  
}  

}

package cn.it.demo1;
/*
* 多线程并发访问同一个数据资源
* 3个线程,对一个票资源,出售
*/
public class ThreadDemo {
public static void main(String[] args) {
//创建Runnable接口实现类对象
Tickets t = new Tickets();
//创建3个Thread类对象,传递Runnable接口实现类
Thread t0 = new Thread(t);
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);

    t0.start();t1.start();t2.start();

}  

}

package cn.it.demo1;
/*
* 采用同步方法形式,解决线程的安全问题
* 好处: 代码简洁
* 将线程共享数据,和同步,抽取到一个方法中
* 在方法的声明上,加入同步关键字
*
* 问题:
* 同步方法有锁吗,肯定有,同步方法中的对象锁,是本类对象引用 this
* 如果方法是静态的呢,同步有锁吗,绝对不是this
* 锁是本类自己.class 属性
* 静态方法,同步锁,是本类类名.class属性
*/
public class Tickets implements Runnable{

//定义出售的票源  
private  int ticket = 100;

public void run(){  
    while(true){  
        payTicket();  
    }  
}

public  synchronized void payTicket(){  
        if( ticket > 0){  
            try{  
               Thread.sleep(10);  
            }catch(Exception ex){}  
            System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);  
        }

}  

}

package cn.it.demo2;
/*
* 多线程并发访问同一个数据资源
* 3个线程,对一个票资源,出售
*/
public class ThreadDemo {
public static void main(String[] args) {
//创建Runnable接口实现类对象
Tickets t = new Tickets();
//创建3个Thread类对象,传递Runnable接口实现类
Thread t0 = new Thread(t);
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);

    t0.start();t1.start();t2.start();

}  

}

package cn.it.demo2;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
* 使用JDK1.5 的接口Lock,替换同步代码块,实现线程的安全性
* Lock接口方法:
* lock() 获取锁
* unlock()释放锁
* 实现类ReentrantLock
*/
public class Tickets implements Runnable{

//定义出售的票源  
private int ticket = 100;  
//在类的成员位置,创建Lock接口的实现类对象  
private Lock lock = new ReentrantLock();

public void run(){  
    while(true){  
        //调用Lock接口方法lock获取锁  
        lock.lock();  
        //对票数判断,大于0,可以出售,变量--操作  
            if( ticket > 0){  
                try{  
                   Thread.sleep(10);  
                   System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);  
                }catch(Exception ex){

                }finally{  
                    //释放锁,调用Lock接口方法unlock  
                    lock.unlock();  
                }  
            }

    }  
}  

}

package cn.itdemo3;

public class DeadLock implements Runnable{
private int i = 0;
public void run(){
while(true){
if(i%2==0){
//先进入A同步,再进入B同步
synchronized(LockA.locka){
System.out.println("if…locka");
synchronized(LockB.lockb){
System.out.println("if…lockb");
}
}
}else{
//先进入B同步,再进入A同步
synchronized(LockB.lockb){
System.out.println("else…lockb");
synchronized(LockA.locka){
System.out.println("else…locka");
}
}
}
i++;
}
}
}

package cn.it.demo3;

public class DeadLockDemo {
public static void main(String[] args) {
DeadLock dead = new DeadLock();
Thread t0 = new Thread(dead);
Thread t1 = new Thread(dead);
t0.start();
t1.start();
}
}

package cn.it.demo3;

public class LockA {
private LockA(){}

public  static final LockA locka = new LockA();  

}

package cn.it.demo3;

public class LockB {
private LockB(){}

public static final LockB lockb = new LockB();  

}

package cn.it.demo4;
/*
* 输入的线程,对资源对象Resource中成员变量赋值
* 一次赋值 张三,男
* 下一次赋值 lisi,nv
*/
public class Input implements Runnable {
private Resource r ;

public Input(Resource r){  
    this.r = r;  
}

public void run() {  
    int i = 0 ;  
    while(true){  
      synchronized(r){  
          //标记是true,等待  
            if(r.flag){  
                try{r.wait();}catch(Exception ex){}  
            }

            if(i%2==0){  
                r.name = "张三";  
                r.sex = "男";  
            }else{  
                r.name = "lisi";  
                r.sex = "nv";  
            }  
            //将对方线程唤醒,标记改为true  
            r.flag = true;  
            r.notify();  
      }  
        i++;  
    }  
}

}

package cn.it.demo4;
/*
* 输出线程,对资源对象Resource中成员变量,输出值
*/
public class Output implements Runnable {
private Resource r ;

public Output(Resource r){  
    this.r = r;  
}  
public void run() {  
    while(true){  
      synchronized(r){  
          //判断标记,是false,等待  
        if(!r.flag){  
            try{r.wait();}catch(Exception ex){}  
        }  
        System.out.println(r.name+".."+r.sex);  
        //标记改成false,唤醒对方线程  
        r.flag = false;  
        r.notify();  
      }  
    }  
}

}

package cn.it.demo4;
/*
* 定义资源类,有2个成员变量
* name,sex
* 同时有2个线程,对资源中的变量操作
* 1个对name,age赋值
* 2个对name,age做变量的输出打印
*/
public class Resource {
public String name;
public String sex;
public boolean flag = false;
}

package cn.it.demo4;
/*
* 开启输入线程和输出线程,实现赋值和打印值
*/
public class ThreadDemo{
public static void main(String[] args) {

    Resource r = new Resource();

    Input in = new Input(r);  
    Output out = new Output(r);

    Thread tin = new Thread(in);  
    Thread tout = new Thread(out);

    tin.start();  
    tout.start();  
}  

}