java 多线程 (面试必回)

一、 线程简介

1.线程:

线程是cpu调度和执行的单位。

2.进程 : 是程序的一次执行过程,是系统资源分配的单位。

一个进程可以有多个线程(不同的线程控制不同的功能)

3.程序

注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核

如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点只能执行一段代码,因为切换很快

二、 线程创建

1. 继承类 Thread 类

( 本质上是 该类实现了 Runable 接口)

步骤:

        (1) 创建线程类继承 Thread 类, 重写run方法

         (2)在主线程main中创建线程类的对象,调用start方法

结果:

注: 线程开启不一定立即执行,由cpu调度执行

注 : 调用run()和start()的区别

public class threadTest extends Thread {
    @Override
    public void run() {
    //在这里重写 该线程的执行逻辑
        for(int i=0;i<100;i++){
            System.out.println("正在执行线程"+i);
        }
    }
    public static void main(String[] args) {
        threadTest t1=new threadTest();
        t1.start();
        for(int i=0;i<1000;i++){
            System.out.println("主线程----"+i);
        }
    }

}

2.实现接口 Runable 接口

步骤:

        (1) 创建线程类 实现了 Runable 接口, 重写run方法

         (2)在主线程main中创建线程类的对象,将线程类对象作为参数传入Thread类的构造器

          (3)Thread类对象调用start方法

public class threadTest2 implements  Runnable{
    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println("正在执行线程"+i);
        }
    }

    public static void main(String[] args) {
        threadTest2 t=new threadTest2();
        //t.run();
        new Thread(t).start();
        for(int i=0;i<1000;i++){
            System.out.println("主线程----"+i);
        }
    }
}

注:该方法 避免单继承的局限性,同一个对象可以被多个线程同时使用

线程创建的两种方法的异同

异:

三、线程的状态

注: 线程进入死亡状态就不能再次使用

四、线程方法

1. 线程停止

有对应让线程停止的方法,但是不建议使用

一般使用的是自己创建的stop方法

(1)设置一个标志位flag

(2)在外部控制线程的执行次数

public class threadTest2 implements  Runnable{
    boolean flag=true;

    @Override
    public void run() {
        // 标志位
        while(flag){

            System.out.println("正在执行线程"+Thread.currentThread().getName());
        }
    }

    //stop()方法
    void stop(){
        flag=false;
    }
    public static void main(String[] args) {
        threadTest2 t=new threadTest2();
        //t.run();
        new Thread(t).start();
        for(int i=0;i<500;i++){
            System.out.println(Thread.currentThread().getName()+" , "+i);
         //程序外面控制线程的运行
            if(i==100)
                t.stop();
        }

    }
}

2.线程休眠

sleep(ms) 指定当前线程阻塞的毫秒数,存在异常 InterruptedException

sleep时间到达后线程进入就绪状态

每个对象都有一个锁,但是sleep不会释放锁

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;

public class testSleep implements Runnable {


    @Override
    public void run() {
        for (int i = 20; i > 0; i--) {
            try {

                Date time = new Date(System.currentTimeMillis());
                System.out.println(i +",currentTime: " + new SimpleDateFormat("HH:mm:ss").format(time));
                Thread.sleep(1000); } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // 写一个倒计时
    public static void main(String[] args) {
        testSleep test = new testSleep();
        new Thread(test).start();
        for(int i=0;i<1000;i++){
            System.out.println(Thread.currentThread().getName());
        }

    }

}

3.线程礼让 yield()

礼让线程:让当前正在执行的线程暂停,但不阻塞,转为就绪状态

让cpu重新调度,礼让不一定成功

4.线程强制执行 join()

待此线程执行完成之后再执行其他线程。

其他线程处于阻塞状态

5. 线程的优先级

先设置线程的优先级,再启动线程

五、线程同步

 1. 多个线程操作同一个资源,需要用到线程同步

2. 同步代码块

本质上是排队+锁

注: 锁可以自己指定,但是必须唯一(对线程来说)

package ThreadTest;

// 三个窗口卖一百张票
public class testTickets extends Thread {
    static int Tickets = 100;
    static Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                if (Tickets > 0) {
                    try {
                        Thread.sleep(10);
                        System.out.println(Thread.currentThread().getName() + ":卖出第" + Tickets-- + "票");

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else break;

            }
        }
    }

    public static void main(String[] args) {
        testTickets t1 = new testTickets();
        testTickets t2 = new testTickets();
        testTickets t3 = new testTickets();
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}
public class testTickets implements  Runnable{
    //
    int Tickets=100;
    // 为什么这里不需要static ?
    // 因为这里的线程是实现了Runnable接口,只会创建一个testTickets对象,所以所有的线程共用一份Tickets
    @Override
    public void run() {
        while(true){
            synchronized (this) {
                if (Tickets > 0) {
                    try {
                        Thread.sleep(100);
                        System.out.println(Thread.currentThread().getName() + ":卖出第" + Tickets-- + "票" + this);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else break;
            }
        }
        //
    }

    public static void main(String[] args) {
        testTickets test=new testTickets();
        Thread t1=new Thread(test,"t1");
        Thread t2=new Thread(test,"t2");
        Thread t3=new Thread(test,"t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

3.同步方法

注:同步方法的锁不能自己指定

 1. 静态 :当前类的字节码文件
 2. 非静态: this 对象
public class testTickets implements Runnable {
    //
    int Tickets = 100;

    // 为什么这里不需要static ?
    // 因为这里的线程是实现了Runnable接口,只会创建一个testTickets对象,所以所有的线程共用一份Tickets
    @Override
    public void run() {
        while (true) {
            if (method()) break;
        }
        //
    }

    //同步方法的锁不能自己指定
    // 1. 静态 :当前类的字节码文件
    // 2. 非静态: this 对象
    private synchronized boolean method() {
        if (Tickets > 0) {
            try {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + ":卖出第" + Tickets-- + "票" + this);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else return true;
        return false;
    }

    public static void main(String[] args) {
        testTickets test = new testTickets();
        Thread t1 = new Thread(test, "t1");
        Thread t2 = new Thread(test, "t2");
        Thread t3 = new Thread(test, "t3");
        t1.start();
        t2.start();
        t3.start();
    }
}



// 三个窗口卖一百张票
public class testTickets extends Thread {
    static int Tickets = 100;
    static Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            if (method()) break;
        }
    }

    private static  synchronized  boolean method() {
        if (Tickets > 0) {
            try {
                Thread.sleep(10);
                System.out.println(Thread.currentThread().getName() + ":卖出第" + Tickets-- + "票" );

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else return true;
        return false;
    }

    public static void main(String[] args) {
        testTickets t1 = new testTickets();
        testTickets t2 = new testTickets();
        testTickets t3 = new testTickets();
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

六、锁

lock

问题: 可否自己设定加锁解锁

LOCK 提供了获得锁和释放锁的方法

1.lock是接口,不能直接实例化,实现类是 ReentrantLock

七、线程池

1.线程池的核心思想:创建容器存储线程

创建线程池,提交任务(提交任务的时候线程池会自动去创建线程)

(1)

public static ExecutorService newCachedThreadPool() 

创建的最大线程数是int型数据的最大值,

// 线程池
public class threadPool implements  Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+","+i);
        }
    }
    public static void main(String[] args) {
        threadPool t1=new threadPool();

        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        cachedThreadPool.submit(t1);
        cachedThreadPool.submit(t1);
        cachedThreadPool.submit(t1);
        cachedThreadPool.submit(t1);
        cachedThreadPool.submit(t1);
    }


}

(2)

public static ExecutorService newFixedThreadPool(int nThreads)
// 线程池
public class threadPool implements  Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+","+i);
        }
    }
    public static void main(String[] args) {
        threadPool t1=new threadPool();

       /* ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        cachedThreadPool.submit(t1);
        cachedThreadPool.submit(t1);
        cachedThreadPool.submit(t1);
        cachedThreadPool.submit(t1);
        cachedThreadPool.submit(t1);

        */
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        fixedThreadPool.submit(t1);
        fixedThreadPool.submit(t1);
        fixedThreadPool.submit(t1);
        fixedThreadPool.submit(t1);
        fixedThreadPool.submit(t1);
        fixedThreadPool.submit(t1);
    }
    
}

自定义线程池

任务拒绝策略

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值