Java编程基础-中级

多线程(总结,先判断是否是多线程(Thread or Runnable or 实现Callable接口 or 使用线程池),再判断是否有线程安全问题(lock or synchronized) ,是否要先后有序执行(lock or notify))线程的知识是真的多

1.基本概念:程序、进程、线程
程序:为了完成特定热舞、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
进程:程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。-生命周期
程序是静态的,进程是动态的。
线程:是一个程序内部的执行路径。
1.进程可进一步细化为线程,若一个进程可以支持多个线程执行,我们可以说它支持多线程。如:360可以同时进行查杀和清理和扫描。
2.线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小
3.一个进程中的多个线程共享相同的内存单元/内存地址空间→他们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简洁、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患。

总结
每个进程独立拥有一个方法区和堆空间。
一个进程的每个线程独立拥有一套虚拟机栈和程序计数器。
一个进程的每个线程共同使用一套方法区和堆。

单核CPU和多核CPU的理解
单核CPU是一种假的多线程,因为在一个时间段内,也只能执行一个线程任务。
过去单核CPU运行多个程序的原理:一个程序运行一个时间段,由于处理时间过快,让人感觉象是进程在并行处理。

对于JAVA应用来说运行当中至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。

并行与并发
并行:多个CPU同时执行多个任务。如多人做多事。
并发:一个CPU执行多个任务。比如:秒杀、多人做同一件事。

2.线程的创建和应用(重点)(共同执行)
方式一:
1.创建一个继承Thread类的子类
2.重写run方法 ---------将此线程的执行操作卸载run方法中
3.创建对象调用start()
注意:调用run方法不能实现多线程。线程只能调用一次,还需要调用只能再new一个方法。

代码

package Day01.Exercise;
/**
 * @Author kevin
 * @Description
 * 创建两个分线程,其中一个线程遍历100以内的偶数,另一个线程遍历100以内的奇数
 *
 *
 * @Create 2021-01-20-11:02
 * @Modify
 */
public class ThreadDemo {
    public static void main(String[] args) {
        threA A =new threA();
        threB B =new threB();
        A.start();
        B.start();
		//new Thread(){
            @Override
            public void run() {
                System.out.println("匿名子类");
            }
        }.start();
    }
}
class threA extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
            if (i%2==0){
                System.out.println(i);
            }
        }
    }
}
class threB extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
                if (i%2!=0){
                    System.out.println(i);
                }
        }
    }
}

4.Thread的方法
1.start()
2.run()
3.currentThread():静态方法,返回执行当前代码的线程(用在一对象多线程)
4.getname
5.setname
6.yield():放弃当前cpu的执行权 总结:礼让
7.线程A.join() :阻塞当前线程直到线程A执行完以后执行 总结:插队
8.stop():强制结束当前进程 不建议使用了
9.sleep():
10.alive():判断当前线程是否存活
代码

public class ThreadDemo {
    public static void main(String[] args) {
        threA A =new threA();
        threB B =new threB();
        A.setName("线程一");
        B.setName("线程二");
        A.start();
        //B.join()                            //这个一般写在主类的方法中,因为是非静态方法,
        											所以不能通过类名调用,需要处理异常。
        B.start();
class threA extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
            if (i%2==0){
                System.out.println(getName()+i);
            }if (i==20){

					//yield();                                        //当线程A执行到20的时候,放弃执行权
            try {
                    sleep(1000);                                //当线程A执行到20的时候,阻塞1秒。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class threB extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 != 0) {
                System.out.println(getName() + i);
            }
        }
    }
}

优先级(set priority)
最高10,最低0, 执行情况是优先级高的先执行的概率高

**这里我有一个记错的地方就是getname的调用不用写类名+.currentThread().getName() 这样显示的不是你改名的getname,是真实的执行的name **

public class PriorityTest {
    public static void main(String[] args) {
        SuperVipPriority svip =new SuperVipPriority("线程一");
        VipPriority vip =new VipPriority("线程二");
        NormalPriority no =new NormalPriority("线程三");
//        svip.setPriority(1);
//        vip.setPriority(2);
//        no.setPriority(3);
        svip.run();
        vip.run();
        no.run();
    }
}

class VipPriority extends Thread {
    public VipPriority(String s) {
        super(s);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(VipPriority.currentThread().getName() + i);
            }
        }
    }
}


class NormalPriority extends Thread{
    public NormalPriority(String s){
        super(s);
    }
    public void run() {
        for (int i = 0; i <100 ; i++) {
            if (i%3==0){
                System.out.println(VipPriority.currentThread().getName()+i);
            }
        }
    }
}


class SuperVipPriority extends Thread{
    public SuperVipPriority(String s){
        super(s);
    }
    public void run() {
        for (int i = 0; i <100 ; i++) {
            if (i%5==0){
                System.out.println(VipPriority.currentThread().getName()+i);
            }
        }
    }
}

窗口买票

package Day01.ThreadWindowTest;

/**
 * @Author kevin
 * @Description  创建三个窗口买票,总票数100张.
 * @Create 2021-01-20-16:44
 * @Modify
 */

public class WindowTest extends Thread{
    private static int  ticket =100;
    public WindowTest(String s){
        super(s);
    }
    @Override
    public void run() {
        while (true) {
            if (ticket > 0) {
                System.out.println(getName() + ticket);
                ticket--;
            } else {
                break;
            }
        }
    }
}

class User{
    public static void main(String[] args) {
        WindowTest w1 =new WindowTest("窗口一出售:");
        WindowTest w2 =new WindowTest("窗口二出售:");
        WindowTest w3 =new WindowTest("窗口三出售:");
        w1.start();
        w2.start();
        w3.start();
    }
}

方式二:
1.写一个A方法实现一个Runnerble的接口,重写run方法,这个时候里面是不能写带参构造器了,因为Runnerable 不提供这样的接口属性接收。同时可以看到Thread 也是实现了Runnerable接口。注意重写方法的时候调用名字必须写Thread.currentThread().getName(),因为Runnerable不提供getname方法。
2.main方法new一个A方法的对象,接着new Thread线程的多个对象,将A丢进Thread()中
3.调用方法。

原理?????/

package day01;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-20-21:54
 */
public class Runnable {
    public static void main(String[] args) {
        test t =new test();
        Thread t1 =new Thread(t);
        Thread t2 =new Thread(t);
        Thread t3 =new Thread(t);
        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");
        t1.start();
        t3.start();
        t2.start();
    }
}
class test implements java.lang.Runnable {
    public int ticket=100;
    @Override
    public void run() {
            while (true) {
                if (ticket>0) {
                System.out.println(Thread.currentThread().getName() + ticket);
                ticket--;
            }else {
                    break;
                }
            }
    }
}

比较创建线程的两种方式
优先选择实现方式
1.继承方式局限性大,实现方式更宽松
2.实现方式更适合处理多个线程有各项数据的情况

联系:都是实现了Runnalble接口

回顾

1.对程序、进程、线程的理解

程序:为完成某种特定任务、用某种语言编写的一组指令集的集合。程序是静态的,未执行的代码

进程:是程序的执行状态

线程:是进程执行任务的任务人,一个进程至少有一个线程在执行,java中进程至少有三个线程

2.代码完成继承Thread的方式创建分线程,并遍历100内的自然数

package day01.Practice;

/**
 * @Author kevin
 * @Description 代码继承Thread 类,并完成100以内的的自然数遍历
 * @Create 2021-01-21-13:58
 * @Modify
 */
public class thread {
    public static void main(String[] args) {
        Method me =new Method();
        me.run();
    }
}
class Method extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
            System.out.println(i);
        }
    }
}

3.代码完成实现Runnable接口的方法创建分线程,并遍历100内的自然数

package day01.Practice;

/**
 * @Author kevin
 * @Description 代码继承Thread 类,并完成100以内的的自然数遍历
 * @Create 2021-01-21-13:58
 * @Modify
 */
public class thread {
    public static void main(String[] args) {
        Method me =new Method();
        Thread t1 =new Thread(me);
        t1.start();
    }
}
class Method implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
            System.out.println(i);
        }
    }
}

同个方法中的线程都有独立的虚拟机栈和程序计数器,共享方法区和堆
同个方法中的线程都有独立的虚拟机栈和程序计数器,共享方法区和堆

3.线程的生命周期
Thread.state:表示生命周期的状态

3.1 新建 new对象
3.2 就绪 start 进入运行队列
3.3 运行 run 开始运行
3.4 阻塞 进程指向别的状态,无法继续进行 join、sleep
3.5 死亡 stop 强制死亡、异常

在这里插入图片描述

4.线程的同步(重难点)

问题背景:当出现多线程共享数据的时候会出现安全问题(以下方法出现在有共享数据的情况),如同一张卡取钱,重票,错票

问题原因:当某个线程未执行完,或执行停滞,另一个线程参与进来。

如何解决:当一个线程在操作共享数据的时候,其他线程不能参与进来。直道线程a操作完后其他线程才可以进来,即使出现阻塞也能改变。

java中,通过同步机制,解决线程安全问题

方式一:同步代码块(synchronized(同步监视器){操作公共数据的代码} static/)

说明:
操作共享数据的代码,即为需要被同步的代码
同步监视器,俗称:锁。任何一个类的对象都可以是锁。!多个线程必须通用一把锁。

package day02.tick;

import java.util.concurrent.Callable;

/**
 * @Author kevin
 * @Description
 * @Create 2021-01-21-14:52
 * @Modify
 */
public class Windows {
    public static void main(String[] args) {
        Station station =new Station();
        Thread A =new Thread(station);
        Thread B =new Thread(station);
        Thread C =new Thread(station);
        A.setName("售票A:");
        B.setName("售票B:");
        C.setName("售票C:");
        A.start();
        C.start();
        B.start();
    }
}
class Station implements Runnable{
    private int ticket =100;
    Object object =new Object();                这种只能有一把锁,
    @Override
    public void run() {
        synchronized (object){                / 这个写的位置貌似不对,这样写只会输出一个
			for{
                if (ticket>0){
                    System.out.println(Thread.currentThread().getName()+ticket);
                ticket--;
                }else{
                break;
                }
            }
        }
    }
}

这个是正确的方法

package day02.tick;

import java.util.concurrent.Callable;

/**
 * @Author kevin
 * @Description
 * @Create 2021-01-21-14:52
 * @Modify
 */
public class Windows {
    public static void main(String[] args) {
        Station station =new Station();
        Thread A =new Thread(station);
        Thread B =new Thread(station);
        Thread C =new Thread(station);
        A.setName("售票A:");
        B.setName("售票B:");
        C.setName("售票C:");
        A.start();
        C.start();
        B.start();
    }
}

class Station implements Runnable{
    private int ticket =100;
    Object object =new Object();
    @Override
    public void run() {
            for (;;) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (object){				//可以改成this 因为都是一个类
                if (ticket>0) {
                    System.out.println(Thread.currentThread().getName()+ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}

使用同步代码块处理继承方式的线程安全问题(二、造一个synchronized方法 静态(处理三个线程三容器)/非静态(处理当容器三线程))

package day02.tick;

import java.util.concurrent.Callable;

/**
 * @Author kevin
 * @Description
 * @Create 2021-01-21-14:52
 * @Modify
 */
public class Windowstest2 {
    public static void main(String[] args) {
            Stationa A =new Stationa();
            Stationa B =new Stationa();
            Stationa C =new Stationa();
            A.setName("售票处A:");
            B.setName("售票处B:");
            C.setName("售票处C:");
            A.start();
            B.start();
            C.start();

    }
}

class Stationa extends Thread{
    public static  int ticket =100;		
    public static Object object =new Object();		//这里要new一个static的对象,
    												不然不共享。
    @Override
    public void run() {
            for (; ; ) {
                synchronized (object ) {						
                    try {
                        Thread.sleep(100);   //这里要睡一下,否则没等到另一个方法拿钥匙来就结束了
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (ticket > 0) {
                    System.out.println(getName() + ticket);
                    ticket--;
                }
            }
        }
    }
}

两个方式的实现区别(一个像并行,一个像并发)
在这里插入图片描述

方式二:同步方法

当方法中是操作共享数据的方法就可以在方法public后加上synchronized ,如果包多了就不好使了。
同步方法解决实现的线程安全问题()

package day01;

/**
 * @autor kevin
 * @detatil 同步方法
 * @create 2021-01-21-21:21
 */
public class Day02 {
    public static void main(String[] args) {
        testa t =new testa();
        Thread t1 =new Thread(t);
        Thread t2 =new Thread(t);
        Thread t3 =new Thread(t);
        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");
        t1.start();
        t3.start();
        t2.start();
    }
}
class testa implements java.lang.Runnable {
    public int ticket=100;

    public synchronized void tt(){
        if (ticket>0) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
                System.out.println(Thread.currentThread().getName() + ticket);
                ticket--;
            }else {
            Thread.currentThread().stop();
        }
    }
    @Override
    public void run() {
        for (;;) {
            tt();
        }
    }
}

同步方法解决继承的线程安全问题(问题:为什么大部分执行的都是一条线?)

package day02;

/**
 * @autor kevin
 * @detatil 同步方法
 * @create 2021-01-21-21:21
 */
public class Windows {
    public static void main(String[] args) {
        testc A =new testc();
        testc B =new testc();
        testc C =new testc();
        A.setName("窗口一:");
        B.setName("窗口二:");
        C.setName("窗口三:");
        A.start();
        B.start();
        C.start();
    }
}
class testc extends Thread {
    public static int ticket=100;

    public static synchronized void Method(){                    
        if (ticket>0){
            System.out.println(Thread.currentThread().getName()+ticket);
            ticket--;
        }else {
            Thread.currentThread().stop();
        }
    }

    @Override
    public void run() {
        for (;;){
            Method();
        }
    }
}

对于使用安全锁解决单例模式的懒汉式

package day02.tick.text;
/**
 * @Author kevin
 * @Description
 * @Create 2021-01-22-9:53
 * @Modify
 */
public class bank implements Runnable {
    private static int number;
    private static String name;
    private static int age;
    private static boolean ismale;
    private static bank instance = null;
   
    private static Object o =new Object();
    private bank() {

    }
    @Override
    public void run() {
        for (; ; ) {
            System.out.println(Thread.currentThread().getName()+getInstance());
        }
    }
    public static bank getInstance() {
        synchronized (o) {
            if (instance == null) {
                instance = new bank();
                return instance;
            } else {
                return null;
            }
        }
    }
}
public class User {
    public static void main(String[] args) {
        bank a =bank.getInstance();
        Thread T1 =new Thread(a);
        Thread T2 =new Thread(a);
        Thread T3 =new Thread(a);
        T1.setName("t1:");
        T2.setName("t2:");
        T3.setName("t3:");
        T1.start();
        T2.start();
        T3.start();
    }
}

线程的死锁问题
死锁
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程死锁,出现死锁后程序不会出现异常,但会出现阻塞。

package day02.tick.ThreadTest;

/**
 * @Author kevin
 * @Description         描述线程的死锁问题
 * @Create 2021-01-22-16:14
 * @Modify
 */
public class Threadtest {
    public static void main(String[] args) {
        StringBuffer a1 =new StringBuffer();
        StringBuffer a2 =new StringBuffer();
        new Thread(){
            @Override
            public void run() {
                synchronized (a1){
                    System.out.println("牛奶");
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                synchronized (a2){
                    System.out.println("咖啡");
                }
            }
        }.start();

        new Thread(new Runnable() {   //这里解释一下,目的是想做一个实现类,但是实现类不能.start。
        													所以这里利用了多态性,
        													传入一个Runnable的匿名实现类,
        													效果就是一个匿名实现类。
            @Override
            public void run() {
                synchronized (a2){
                    System.out.println("后街");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                synchronized (a1){
                    System.out.println("男孩");
                }
            }
        }).start();
    }
}

JDK5.0开始加入Lock(锁)解决线程的安全问题
synchronized和lock的异同
相同:都是用来处理线程安全问题
不同:手动结束和自动结束lock的功能更广泛
优先使用lock方法
代码

package day02.tick.ThreadTest;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author kevin
 * @Description    //解决线程问题的方式三;lock锁
 * @Create 2021-01-22-19:26
 * @Modify
 */
public class LockTest {
    public static void main(String[] args) {
        Window window =new Window();
        Thread A =new Thread(window);
        Thread B =new Thread(window);
        Thread C =new Thread(window);
        A.setName("售票处A:");
        B.setName("售票处B:");
        C.setName("售票处C:");
        A.start();
        B.start();
        C.start();
    }
}

class Window implements Runnable{
    //1.实例化一个lock;
    private ReentrantLock lock =new ReentrantLock();
    private int ticket =100;
    @Override
    public void run() {
        while (true) {
            try {
                //2.调用lock方法
                lock.lock();
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ticket);
                    ticket--;
                } else {
                    break;
                }
            }finally {
                //3.解锁
                lock.unlock();
            }
        }
    }
}

银行存钱例子

package day02.tick.Pracktice;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author kevin
 * @Description     银行有个账户分别有2人存入3000,每人没别一次接一次公平存1000。打印结果
 * @Create 2021-01-22-19:45
 * @Modify
 */
public class Bank {
    public static void main(String[] args) {
            Account account =new Account();
            Thread A =new Thread(account);
            Thread B =new Thread(account);
            A.setName("A用户存入:");
            B.setName("B用户存入:");
            A.start();
            B.start();
    }
}
class Account implements Runnable{
    ReentrantLock lock =new ReentrantLock(true);
    private int wealth=0;
    @Override
    public void run() {
        for (int i = 0; i <3 ; i++) {
            lock.lock();
            try {
                wealth += 1000;
                System.out.println(Thread.currentThread().getName() + wealth);
            } finally {
                lock.unlock();
            }
        }
    }
}

5.线程的通信(notify/wait)
实现一个线程一个线程有序的执行。
当一个线程执行完毕后wait一下顺便释放锁,等到另一个线程拿到锁进来唤醒它,从而实现一个接一个的输出。
注意:
1.sleep锁不释放,wait释放
2.对于notify来说,同一把锁貌似还是会报错,跑的两个方法必须来自同一个类才行,这是一个苛刻的条件。附上代码

package PrroductTest;
/**
 * @autor kevin
 * @detatil   一个商店,一个生产者,两个消费者,没有产品wait释放锁,产品过多wait释放锁。
 * @create 2021-01-23-21:35
 */
public class ProductTEST {
    public static void main(String[] args) {
        Clerk clerk =new Clerk();
        Producer P =new Producer(clerk);
        Consumer C = new Consumer(clerk);
        Consumer D =new Consumer(clerk);
        P.setName("P生产了一件,总共有:");
        C.setName("C消费了一件,总共有:");
        D.setName("D消费了一件,总共有:");
        P.start();
        C.start();
        D.start();
    }
}
package PrroductTest;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-23-21:36
 */
public class Consumer extends Thread {
    Clerk clerk ;
    public Consumer(Clerk clerk){
        this.clerk=clerk;
    }
    @Override
    public void run() {
        for (;;) {
            clerk.c(); //我原来把方法写在里面的,调用syg方法用同一把锁没问题,但调用notify方法报错,必须要同一个类才行,所以把两个方法封装的一个类里面,然后两个都调用同一个方法。
        }
    }
}

package PrroductTest;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-23-21:36
 */
public class Clerk {
    public int goods =0;
    public synchronized void p(){
            notify();
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (goods < 20) {
                goods++;
                System.out.println(Thread.currentThread().getName() + goods);
            } else {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
    public synchronized void c(){
            notify();
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (goods > 0) {
                goods--;
                System.out.println(Thread.currentThread().getName() + goods);
            } else {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

package PrroductTest;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-23-21:36
 */
public class Producer extends Thread {
    Clerk clerk =new Clerk();
    public Producer(Clerk clerk){
        this.clerk=clerk;
    }
    @Override
    public void run() {
        for (;;) {
                clerk.p();     //我原来把方法写在里面的,调用syg方法用同一把锁没问题,但调用notify方法报错,必须要同一个类才行,所以把两个方法封装的一个类里面,然后两个都调用同一个方法。
            }
        }
    }

6.JDK5.0新增创建方式(实现Callable接口、使用线程池)
实现Callable接口(感觉非常麻烦)
实现Callable接口。----jdk 5.0新增

  •     1.创建一个实现类。
    
  •     2.实现call方法,将此线程需要执行的操作丢到call方法中。
    
  •     3.创建Callable接口是新类的对象。
    
  •     4.将此Callable接口是新类的对象作为传递到FutureTask构造器中,创建FutureTask对象。
    
  •     5.get()返回值即为FutureTask构造器参数Callable实现类重写的call()返回值。
    
  •    6.创建Thread对象,把FutureTask 对象丢进去,然后RUN
    
  • 优点
    1.可以有返回值
    2.可以抛异常
    3.支持泛型
package Threadnew;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @autor kevin
 * @detatil 实现Callable接口。----jdk 5.0新增
 *         1.创建一个实现类。
 *         2.实现call方法,将此线程需要执行的操作丢到call方法中。
 *         3.创建Callable接口是先烈的对象。
 *         4.将此Callable接口是新类的对象作为传递到FutureTask构造器中,创建FutureTask对象。
 *         5.get()返回值即为FutureTask构造器参数Callable实现类重写的call()返回值。
 *
 * @create 2021-01-23-22:26
 */
class NumThread implements Callable{

    @Override
    public Object call() throws Exception {
        int k = 0;
        for (int i = 0; i <= 100; i++) {
            if (i % 2 == 0) {
                k += i;
            }
        }return k;
    }
}
public class ThreadNew {
    public static void main(String[] args){
        NumThread numThread =new NumThread();
        FutureTask futureTask =new FutureTask(numThread);  //这样就可以调用get方法,回调call的返回值
        Thread t =new Thread(futureTask);
        t.start();
        try {
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}

使用线程池(这个是使用最多的-------)
背景:经常创建线程和销毁线程、使用量特别大的资源,比如并发情况下的线程,对性能的影响很大。
思路:提前创建好多线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁船舰销毁、显示重复利用。类似生活中的公共交通工具。
好处:
提高响应速度(减少创建新线程的时间)
降低资源销毁(重复利用线程池中的线程,不需要每次都创建)
便于线程管理
corePoolSize:核心池的大小啊
maximumPoolSize 最大线程数量
keepAliveTime:线程没有任务时最多保持多长时间后会终止

使用

  • 创建一个ExecutorService接口的实现类Executors.new???
  • 如: ExecutorService service =Executors.new???
  • 这个接口有一个静态方法时用来执行线程的,但需要一个Runnable的实现类,这里一般就写好一个实现Runnable的方法套进去。
  • service.excute(T1);//可以再new一个方法来做双线程

代码

package ThreadPool;

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

/**
 * @autor kevin
 * @detatil 方法  1.提供指定数量的线程池
 *               		   2.提供一个实现Runnable接口或Callable接口实现类的对象 并执行.
 *              		   3.关闭连接池
 * @create 2021-01-23-23:12
 */
class NumberThread implements Runnable{

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

public class POOL {
    public static void main(String[] args) {
        //创建一个你选择的功能给这个接口。
        ExecutorService service= Executors.newFixedThreadPool(10);
        service.execute(new NumberThread());//适合使用于Runnable
        service.execute(new NumberThread());//双线程
        //service.shutdown();//关闭线程池
        //service.submit();//适合使用于Callable;

    }

}

补充一个线程池的管理办法。

ExecutorService service = Executors.newFixedThreadPool(10);
        //设置线程池的属性
        //这里强转说明一下:这个ExecutorService接口没有什么方法和属性,把他强转成一个重写方法的子类,
        // 就可以调用多个方法,这里实现了线程池的管理性。
        ThreadPoolExecutor Service =(ThreadPoolExecutor) service;
        Service.setCorePoolSize(15);

问题

这里补充一个结论 , synchronized方法内使用notify,初步判断必须是锁的拥有类才能调用notify,否则报错),同时锁又要满足只能同用一把才有效,因此只能两线程拥有一个类,类里面操作共享数据,以类为锁,同时也是锁的拥有者,同时也唯一

package day02.ThreadPractice;

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

/**
 * @autor kevin
 * @detatil  利用线程池,模拟一个上楼的方式,一楼分左右脚两个线程(当共享数据在1-10)
 *                                      二楼分左右脚两个线程(当共享数据在10-20)
 *                                      三楼输出到达楼顶一个线程(当共享数据在20)
 * @create 2021-01-25-20:21
 */
public class User {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        CommonData data =new CommonData();
        service.execute(new FloorA(data));
        service.execute(new FloorB(data));
        service.execute(new FloorC(data));
        service.execute(new FloorD(data));
        service.execute(new FloorE(data));
    }
}
package day02.ThreadPractice;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-25-20:31
 */
public class CommonData {
    public int step =0;
    public synchronized void Metodf1(){
        notify();
        if (step < 10) {
            step++;
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":我还在一楼的第" + step +
                    "个阶梯");
        }
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

    public synchronized void Metodf2(){
        notify();
        if (step > 10 && step <20) {
            step++;
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + ":我还在二楼的第" + step +
                    "个阶梯");
        }
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

    }
    public synchronized void Metodf3(){
        if (step > 20) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + ":我还在楼的第" + step +
                    "个阶梯");
        }
    }
}

package day02.ThreadPractice;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-25-20:23
 */
public class FloorA implements Runnable {
    CommonData data;
    public FloorA(CommonData data){
        this.data=data;
    }
    @Override
    public void run() {
        for (;;) {
            Thread.currentThread().setName("左脚前进");
            data.Metodf1();
        }
    }
}

package day02.ThreadPractice;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-25-20:20
 */
public class FloorB implements Runnable {

    CommonData data;

    public FloorB(CommonData data) {
        this.data = data;
    }

    @Override
    public void run() {
        for (; ; ) {
            Thread.currentThread().setName("右脚前进");
            data.Metodf1();
        }
    }
}

package day02.ThreadPractice;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-25-20:23
 */
public class FloorC implements Runnable {
    CommonData data;

    public FloorC(CommonData data) {
        this.data = data;
    }
    @Override
        public void run () {
            for (; ; ) {
                Thread.currentThread().setName("右脚前进");
                data.Metodf2();
            }
        }
    }

package day02.ThreadPractice;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-25-20:23
 */
public class FloorD implements Runnable {
    CommonData data;

    public FloorD(CommonData data) {
        this.data = data;
    }
    @Override
    public void run() {
        for (; ; ) {
            Thread.currentThread().setName("左脚前进");
            data.Metodf2();
        }
    }
    }

package day02.ThreadPractice;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-25-20:23
 */
public class FloorE implements Runnable {
    CommonData data;

    public FloorE(CommonData data) {
        this.data = data;
    }
    @Override
    public void run() {
            Thread.currentThread().setName("到达楼顶");
            data.Metodf3();

    }
}

Java常用类

1.字符串相关的类(String)
1.1Sring是一个 不可变 的序列,因为它是char型数组并且是final的
String是引用数据类型,与其他引用数据类型不同的是,他申明在方法区内,一旦创建新的String(char型数组),如果方法区没有就是生成一个(new),同时,如果我们改变这个String的值,它就会先找方法区有没有这个值,如果没有就开辟一个空间,获得这个值的地址值,并不改变原来的值。
例子

public class Study {
    public static void main(String[] args) {
        String s1="abc";
        String s2 =s1;
        s1+="def";
        System.out.println(s1);
        System.out.println(s2);

    }

1.2String赋值方式(实例化,赋值)

String s1 =new Stirng("abc")   //这个在堆空间开辟,但是会在堆空间中指一个地址到方法区
Sring s3 =new Sring ("abc")
String s2 ="abc"			//这个是方法区中 
String s4 ="abc"

这里就有一个区别了
如:s1s2? s1s3? s1.equals(s3)? s2quals(s4)?

问题

package day03;

/**
 * @autor kevin
 * @detatil
 * @create 2021-01-26-20:58
 */
public class Study {
    public static void main(String[] args) {
        me m1 =new me();
        me m2 =new me();
        System.out.println(m1.name==m2.name);//false?
        m1.name ="nihao";
        System.out.println(m1.name==m2.name);
    }
}
class me{
    public String name ="tom";
    public int age =23;
}

问题
结论:String涉及的加减如果有变量,都相当于new了一个对象,对象获得方法区的String地址值。1.常量与常量的凭借结果在常量池。且常量池中不会存在相同内容的常量2.String加减其中有一个是变量,结果就在堆中。3.如果拼接的结果调用intern()方法,返回值就在常量池中 例如:

public class Review {
    public static void main(String[] args) {
        String F ="defg";
        String B = "abcd" +"defg";
        //String B = "abcd" +F;
        String C ="abcddefg";
        System.out.println(B==C);
    }
}

这个是拼接例子

public class Study {
    public static void main(String[] args) {
        String s1 ="hello";
        String s2 ="world";
        String s3 ="helloworld";
        String s4 ="hello"+"world";
        String s5 ="hello" +s2;
        String s6 =s1+"world";
        System.out.println(s3==s4);?
        System.out.println(s3==s5);?
        System.out.println(s3==s6);?
    }
}

继续引入intern方法(确定调用对象的常量池)

public class Study {
    public static void main(String[] args) {
        String s1 ="hello";
        String s2 ="world";
        String s3 ="helloworld";
        String s4 ="hello"+"world";
        String s5 ="hello" +s2;
        String s6 =s1+"world";
        String s7 =s5.intern();
    	System.out.println(s7==s3)
    }
}

最后一个问题提高提(String的不可变性,和值传递机制)

public class Practice {
    public static void main(String[] args) {
        tt t =new tt();
        t.change(t.name);
        System.out.println(t.name);
    }
}
class tt{
    public String name ="kevin";
    public void change(String name){
        name="durant";
    }
}

String的常用方法

  •       1. int length():返回字符串的长度:return value.length
    
  •      2.char charAt(int index):返回某索引处的字符return value[index]
    
  •      3.boolean isEmpty():判断是否是空字符串 :return value.length ==0;
    
  •      4.String tolowerCase():使用默认语言环境,将String中所有字符转换为小写
    
  •      5.String toUpperCase():使用默认语言环境,将String中所有字符转换为大写
    
  •      6.String trim():返回字符串的副本,去掉首位空白,
    
  •      7.boolean equals(Object obj):基表字符串的内容是否相同
    
  •      8.boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
    
  •      9.String concat(String str):将制定字符串连接到此字符串的结尾。等价于"+"
    
  •      10.int compareTo(String anotherString):比较两个字符串大小,一个一个比
    
  •      11.String substring(int beginIndex):返回一个新字符串,他是此字符串的从beginIndex开始截取
    
  •      12.String substring(int beginEndex,int endIndex):返回一个新字符串,他是此字符串从begin开始截取,end结尾。左闭右开
    
  •      13.String endsWith(Sting suffix):测试是否以XX结束的:
    
  •      14.String startsWith(Sting suffix):测试是否以XX开始的:
    
  •      15.boolean contains(CharSequence s):当且仅当此字符串包含制定的char值序列时,返回ture
    
  •      16.int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
    
  •      17.int indexOf(String str,int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从第几位开始找
    
  •      18.int lastIndexOf(String str):返回指定字符串在此字符串中最右边出现处的索引
    
  •      19.int lastIndexOf(String str,int fromIndex):返回制定字符串在此字符串中最后一次出现处的索引,从第几位开始找
    
  •       替换
    
  •      20.String replace(char oldChar,char newChar)
    
  •      21.String replace(CharSequence target,CharSequence replacement):
    

String 的转换
String 与char型数组的转换

  • String.toCharArray();
  • String j =new String(new char[]{1});

String StringBuffer StringBuilder 三个的区别

  •      String:不可变的字符序列
    
  •             底层使用char型数组
    
  •      StirngBuffer(开发中建议使用):可变的字符序列(线程安全,效率低)
    
  •                   底层使用char型数组
    
  •      StringBuilder:可变的字符序列(线程不安全,效率高)
    
  •                    底层使用char型数组
    

StringBuffer的方法(基于String扩充)
1.append 增加
2.delete 删除
3.replece 替换
4.insert 插入
5.reverse 反转
6.indexof 返回指定字符的位置
7.substring 返回指定开始至结尾的字符
8.charAt 放回指定位置的字符。

String StringBuffer StringBuilder 三个转换

StringBuffer s =new StringBuffer();
        String a = new String(s);
        StringBuffer k =new StringBuffer(a);

2.JDK之前的日期时间API
获取当前的时间戳(在system类中)
long time =System.currentTimeMillis();(时间戳和现在时间的以毫秒为单位的时间差)

Date类
java.util.Date类 (父)
java.sql.Date类 (子)

1.两个构造器的使用
java.util.Date类

  Date date =new Date();
        System.out.println(date.toString()); 输出一个当前时间

获取时间戳

Date date =new Date();
        System.out.println(date.getTime());

创建 java.util.Date类的对象

Date date =new Date(1234567981230L);
        System.out.println(date);

java.sql.Date类创建对象

java.sql.Date date1 = new java.sql.Date(111111112456123456l);
        System.out.println(date1.toString());

2.两个方法的使用(通过构造器相互转换)

String D = "2020-09-08";
        Date d =new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //将String转换为Date类
        d=sdf.parse(D);
        //Date类转换为 sql.Date
        java.sql.Date dd=new java.sql.Date(d.getTime());
       //sql.Date类转为Date
       Date jj =new Date(dd.getTime());

复习题

/**
 * @autor kevin
 * @detatil 1.模拟一个trim方法,去除字符串两端的空格。
 *          2.将一个字符串进行反转。将字符串中指定部分进行反转。如'abcdefg'反转'abfedcg'
 *          3.获取一个字符串在另一个字符串中出现的次数。
 *            比如:获取‘ab’再“abkkcadkabkebfkabkkskab”中出现的次数
 *          5.获取两个字符串中最大相同字串。比如:
 *          str1=“abcwerthelloyuiodef”;str2=”cvhellobnm“
 *          提示将短的那个串进行长度依次递减的字串于较长的串比较.
 *
 * @create 2021-02-24-11:30
 */
public class Pra {
    public static void main(String[] args) {
        //第一题
        String s = "    abc    ";
        System.out.println(s.trim());
        //第二题
        String k ="abcdefg";
        System.out.println(k.replace(k.substring(2,5),"edc"));
        //第三题
        String l ="abkkcadkabkebfkabkkskab";
        String j ="ab";
        int q =0;
        for (int i = 0; i <22 ; i++) {
            i=l.indexOf("ab",i);
            q++;
        }
        System.out.println(q);
        //第四题
        String w ="abcwerthelloyuiodef";
        String g ="cvhellobnm";
        char[] n = g.toCharArray();
//        System.out.println('c'+0);
        int p =0;
        for (int i = 0; i <g.length(); i++) {
            if (w.contains(String.valueOf(n[i])) && p<n[i]+0){
                p=n[i]+0;
            }
        }
        System.out.println(p);
    }
}

3.jdk8中新日期时间API
simpledateformat类(里面提供了日期转换的方法)

@autor kevin
 * @detatil 1.System类中currentTimeMillis();
 *          2.java.util.Date和子类java.sql.Date
 *          3.SimpleDateFormat
 *              1.格式化:日期-->字符串
 *              2.解析:字符串-->日期
 *              3.实例化
 *          4.Calendar
 * @create 2021-02-24-22:00
 */
public class time {
    @Test
    public void method() throws ParseException {
        //实例化
        SimpleDateFormat se =new SimpleDateFormat();
        //格式化:日期-->字符串
        Date date =new Date();
        String d =se.format(date);
        System.out.println(d);
        //解析:字符串-->日期
        date = se.parse(d); //抛异常,担心输入格式不对
        System.out.println(date);
        //使用其他的构造器,构造别的日期格式
        SimpleDateFormat tes =new SimpleDateFormat("yyyy.MMMMM.dd GGG hh:mm aaa");
        System.out.println(tes.format(date));
    }
}

课后练习


4.Java比较器
5.System类
6.Math类
7.BigInteger与BigDecimal

枚举类&注解

Java集合

泛型

IO流(input、output)

网络编程(网络数据传输)

Java反射机制

Java8的其他型特性

Java9&Java10&Java11新特性

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值