【2019.10.08】Java 多线程与锁的用法

  • 并发:指两个或多个事件在同一个时间段内发生 交替执行

  • 并行:指两个或多个事件在同一时刻发生(同时发生) 同时执行

  • 进程:一个内存中运行的应用程序

  • 线程:是进程的一个执行单元,负责程序的执行 效率高,多个线程之间互不影响

线程

创建线程2中方法

一、 将类声明为Thread类的子类,该子类重写Thread类的run方法。

实现步骤:

  1. 创建Thread类的子类
  2. 在Thread类的子类中重写Thread类中的run方法。设置线程任务(开启线程要做什么)
  3. 创建Thread类的子类对象
  4. 调用Thread类中的方法 start,开启新的线程,执行run方法
public class MyThread extends Thread {

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

public class Demo01Thread {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();

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

    }
}

  • Thread类中的方法
    • getName() 返回该线程的名称
    • currentThread() 获取到当前正在执行的线程
    • SetName(String name) 设置线程的名称 或者在Thread类中蛇者带参数的构造方法, super(name)
    • sleep() 使当前正在执行的线程以指定的毫秒数暂停
二、 第二种方法:声明实现Runable接口的类。实现run方法

实现步骤

  1. 创建一个Runnable接口的实现类
  2. 在实现类中重写 Runnable接口的run方法,设置线程任务
  3. 创建一个Runnable接口的实现类对象
  4. 创建Thread类对象,构造方法中传递Runnable接口的实现类对象
  5. 调用Thread类中的start方法,开启新的线程执行run方法
实现Runnable接口创建多线程程序的好处:
  1. 避免了单继承的局限性
    1. 一个类只能继承一个类,类继承了Thread类就不能继承其他的类
    2. 实现Runnable接口还可以继承其他的类,实现其他的接口
  2. 增强了程序的扩展性,降低了程序的耦合性
    1. 实现Runnable接口的方法,把设置线程任务和开启新线程进行了分离(解耦)
    2. 实现类中,重写了run方法,用来设置线程任务
    3. 创建Thread类对象,调用start方法,用来开启新的线程
匿名内部类的方式实现线程的创建
  • 简化代码:
    • 把子类继承父类,重写父类的方法,创建子类对象合成一步完成
    • 把实现类实现类接口,重写接口的方法,创建实现类对象合成一步完成

线程安全问题

多线程访问共享数据,会产生线程安全问题
想吃安全问题是不能产生的,我们可以让一个线程在访问共享数据的时候,无论是否失去了cpu的执行权,让其他的线程只能等待

保证:只有一个线程在执行

  • 解决线程安全问题:三种方法
    1. 同步代码块
    2. 同步方法
    3. Lock锁机制
1、解决线程安全问题 ----同步代码块
解决线程安全问题的一种方案:使用同步代码块
        synchronized(锁对象){}

注意:
1. 通过代码块中的锁对象,可以使用任意的对象
2. 但是必须保证多个线程使用的锁对象是一个
3. 锁对象的作用:把同步代码锁住,只让一个线程在同步代码块中执行

同步技术的原理:

  • 使用了一个锁对象,这个锁对象叫做同步锁,也叫异步锁,也叫作对象监视器
  • 同步中的线程,没有执行完毕不会释放锁。同步外的线程没有锁进不去同步
2、解决线程安全问题 ----同步方法

使用步骤:
1. 把访问了共享数据的代码抽取出来,放到一个方法中
2. 在方法上添加synchronized 修饰符
格式:
修饰符 synchronized 返回值类型 方法名(参数列表){}

原理:
同步方法也会把方法内部的代码锁住
只让一个线程执行
同步方法的对象就是是实现类对象 new RunnableImpl()
也就是this

静态方法的锁对象是本类的class属性 --> class 文件对象(反射)

2、解决线程安全问题 ----使用Lock锁

Lock接口中的方法
- lock()
- unlock()

实现步骤:
1. 在成员位置创建一个Reentrantlock对象
2. 在可能会出现安全问题的代码前调用Lock接口中的方法lock 获取锁
3. 在可能会出现安全问题的代码前调用Lock接口中的方法unlock释放锁

线程的状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mixNa07z-1570465532094)(en-resource://database/7492:1)]

新建(NEW)、运行(RUNNABLE)、阻塞(BLOCK)、死亡、睡眠、无限等待(WAITING)

  • wait

  • sleep

  • notify

1、线程间通信
多个线程在处理同一个资源,但处理的动作(线程的任务)不同

2、生产者消费者问题

线程池

线程池:容器 --> 集合(ArrayList, HashSet, LinkedList, HashMap)
LinkedList

当程序第一次执行的时候,创建多个线程,保存在一个集合中,当我们想要使用线程的时候,就可以从集合中取出来线程使用。

在JDK1.5之后,JDK内置了线程池,我们可以直接使用。
java.util.concurrent.Executor线程池的工厂类,用来生成线程池
Executors类中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用的固定线程数的线程池

  • ExecutorService 线程池接口

    • 用来从线程池中获取线程,调用start方法,执行线程任务
      • submit(Runnable task)提交一个 Runnable 任务用于执行
    • 关闭/销毁线程池的方法
      • void shutdown()

    线程池的使用步骤

    • 使用线程池的工厂类 Executor 里面提供的荆条方法 newFixedThreadPool 生成一个指定线程数量的线程池
    • 创建一个类,实现Runnable接口,重写run方法,设置线程任务
    • 调用ExecutorService中的方法 submit ,传递线程任务(实现类)。开启线程,执行run方法
    • 调用ExecutorService中的方法 shutdown,销毁线程池
package ybs.paulson.ThreadPool;

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

/*
  - 使用线程池的工厂类 Executor 里面提供的荆条方法 newFixedThreadPool 生成一个指定线程数量的线程池
   - 创建一个类,实现Runnable接口,重写run方法,设置线程任务
   - 调用ExecutorService中的方法 submit ,传递线程任务(实现类)。开启线程,执行run方法
   - 调用ExecutorService中的方法 shutdown,销毁线程池
 */
public class Demo01ThreadPool {
    public static void main(String[] args) {
        // 1、使用线程池的工厂类 Executor 里面提供的荆条方法 newFixedThreadPool 生成一个指定线程数量的线程池
        ExecutorService es = Executors.newFixedThreadPool(2);
        // 3、 调用ExecutorService中的方法 submit ,传递线程任务(实现类)。开启线程,执行run方法
        // 线程池会一直开启,使用完了线程,会自动的把线程还给线程池,线程可以继续使用
        es.submit(new RunnableImpl());  // 创建新的线程
        es.submit(new RunnableImpl());
        es.submit(new RunnableImpl());
        es.submit(new RunnableImpl());
        es.submit(new RunnableImpl());
        es.shutdown();
//        es.submit(new RunnableImpl());  // 抛出异常,线程池没有了,不能获取线程


    }
}

package ybs.paulson.ThreadPool;

public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        // 1、创建一个类,实现Runnable接口,重写run方法,设置线程任务
        System.out.println(Thread.currentThread().getName() + "创建了一个新的线程");

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值