Java多线程(四种创建方法)——笔记

Java多线程(四种创建方法)——笔记

尚硅谷:https://www.bilibili.com/video/BV1Kb411W75N?p=406

1. 创建多线程

1.1 方式一:继承Thread类

  1. 创建继承Thread的子类

  2. 重写run()方法

  3. 创建Thread类的子类的对象

  4. 通过对象调用start()

    class MyThread extends Thread{
        public void run(){
            
        }
    }
    public class ThreadTest{
        public static void main(String[] args){
            MyThread my = new MyThread();
            my.start();
        }
    }
    
1.1.2

通过创建Thread类的匿名子类的方式

public class ThreadTest{
    public static void main(String[] args){
        new Thread(){
            public void run(){

            }
        }.start();
    }
}

1.2 方式二:实现Runnable接口

  1. 创建一个实现了Runnable接口的类

  2. 实现类去实现Runnable中的抽象方法:run()

  3. 创建实现类的对象

  4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

  5. 通过Thread类的对象调用start()

    class MyThread implements Runnable{
        public void run(){
            
        }
    }
    
    public class ThreadTest{
        public static void main(String[] args){
            MyThread myThread = new MyThread();
            Thread t1 = new Thread(myThread);
            t1.start();
        }
    }
    
    new Thread(new Runnable(){
        public void run(){
    
        }
    }).start();
    

1.3 方式三:实现Callable接口

  1. 创建一个实现Callable接口的实现类

  2. 实现call方法,将此线程需要执行的操作声明在call()中

  3. 创建Callable接口实现类的对象

  4. 将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象

  5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()

  6. 获取Callable中call方法的返回值

// 1.创建一个实现Callable接口的实现类
class MyThread implements Callable {
	// 2.实现call方法,将此线程需要执行的操作声明在call()中
    @Override
    public Object call() throws Exception {
        return null;
    }
}

public class CallableTest {
    public static void main(String[] args) {
        // 3.创建Callable接口实现类的对象
        MyThread myThread = new MyThread();
		// 4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象
        FutureTask futureTask = new FutureTask(myThread);
        // 5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
        new Thread(futureTask).start();
        try {
            // 6.获取Callable中call方法的返回值
            Object o = futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Callable接口比Runnable接口创建多线程更强大?

  1. call()方法有返回值
  2. call()方法可以抛出异常,并被捕获异常
  3. Callable支持泛型

1.4 方式四:线程池

好处:

  1. 提高响应速度(减少了创建线程的时间)
  2. 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  3. 便于线程管理
  • corePoolSize:核心池的大小
  • maximumPoolSize:最大线程数
  • keepAliveTime:线程没有任务时最多保持多长时间后会终止
class MyThread implements Runnable{
    @Override
    public void run() {

    }
}
public class ThreadPool {
    public static void main(String[] args) {
        // 1.提供指定线程数量的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
        // 设置线程池的属性
        service1.setCorePoolSize(15);
        // 2.执行指定的线程的操作
        service.execute(new MyThread());// 适用于Runnable
       // service.submit(new MyThread());// 适用于Callable
        // 3.关闭连接池
        service.shutdown();
    }
}

2.常用方法

方法说明
start()启动当前进程,调用当前进程的run()
run()通常需要重写Thread类中的此方法,将创建的进程要执行的操作声明在此方法中
currentThread()静态方法,返回执行当前代码的线程
getName()获取当前线程的名字
setName()设置当前线程的名字
yield()释放当前cpu的执行权
join()在线程A中调用线程B的join(),此时线程A就进入阻塞状态,直到线程B完全执行完以后,线程a才结束阻塞状态
sleep(long millitime)让当前线程睡眠指定的millitime毫秒,在指定的时间内,当前线程是阻塞状态。
isAlive()判断当前线程是否存活

3.优先级

1.

  • MAX_PRIORITY:10
  • MIN_PRIORITY:1
  • NORM_PRIORITY:5 默认优先级

2.获取和设置当前线程的优先级

  • getPriority():获取线程的优先级

  • setPriority(int p):设置线程的优先级

    thread,setPriority(MAX_PRIORITY)
    

    注意:高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。

4. 线程安全

以买票为例,

问题:卖票过程中,出现了重票,错票–>出现了线程的安全问题

原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程进入操作

解决:当一个线程a在操作时,其他线程不能进入,直到a完成

1.方式一:同步代码块

synchronized(同步监视器){
    // 需要被同步的代码,即操作共享数据的代码
}

说明:

  • 需要被同步的代码:即操作共享数据的代码 代码不能包含多了,也不能少了

  • 同步监视器:俗称:“锁“,任何一个类的对象都可以充当锁

  • 多个线程必须共用同一把锁

    • 一、
    // 一、继承Thread
    private static Object obj = new Object();
    // 二、实现Runable
    Object obj = new Object();
        
    public void run(){ 
        synchronized(obj){ // 使用obj作为同步监视器
            // 需要被同步的代码,即操作共享数据的代码
        }
    }
    
    • 二、
      // 一、继承Thread  慎用this充当同步监视器,可以考虑使用当前类的对象充当同步监视器
      synchronized(MyThread.class){  // Class clazz = MyThread.class ; MyThread.class只会加载一次
                  // 需要被同步的代码,即操作共享数据的代码
      }
    
      // 二、实现Runable  可以考虑使用this充当同步监视器
      synchronized(this){  // this:唯一的XXX类的对象
                  // 需要被同步的代码,即操作共享数据的代码
      }   
    
  • 操作同步代码时,只能有一个线程参与,相当于是一个单线程的过程,效率低。

2.方式二:同步方法

  • 仍然涉及同步监视器,不需要显式声明
  • 非静态的同步方法,同步监视器是:this
  • 静态的同步方法,同步监视器是:当前类本身
// 二、实现Runable
public void run(){ 
   // 调用同步方法
}
	// 同步方法
private synchronized void show(){ // 同步监视器:this
    // 需要被同步的代码,即操作共享数据的代码
}

// 一、继承Thread
public void run(){ 
   // 调用同步方法
}
	// 同步方法
private static synchronized void show(){ // static 唯一  同步监视器:当前类
    // 需要被同步的代码,即操作共享数据的代码
}

3.方式三:Lock锁

// 一、Runnable
// 1. 实例化ReentrantLock
private ReentrantLock lock = new ReentrantLock();
public void run(){
    try{
        // 2.调用锁定方法lock()
        lock.lock();
        //同步代码
    }finally{
        // 3.调用解锁方法unlock()
        lock.unlock();
    }
}
// 二、继承Thread
private static ReentrantLock lock = new ReentrantLock();

5.将单例模式中的懒汉式改为线程安全

class Bank{
    private Bank(){}
    private static Bank instance = null;
    public static synchronized Bank instance(){
        if (instance = null){
            synchronized(Bank.class){
                if (instance = null){
                	instance = new Bank();
                }
            }
        }
        return instance;
    }
}

6.死锁

  • 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。

  • 不会报错,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。

解决:

  • 专门的算法,原则
  • 尽量减少同步资源的定义
  • 尽量避免嵌套同步

7.线程通信

java.lang.Object

  • wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
  • notify():一旦执行此方法,就会唤醒被wait的一个线程;如果有多个线程被wait,按优先级唤醒
  • notifyAll():一旦执行此方法,就会唤醒所有被wait的线程

必须使用在同步代码块中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIN丶虫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值