在我们开始今天的线程之前,我们先来几道干货,是什么呢?就是我们一般取公司面试可能会被问道的面试题:
1,描述java中多线程运行原理,
2,会用继承方式的会创建多线程,
3,会用实现接口的方式的会创建多线程
4,能够说出线程6个状态的名称,
5,能够解决线程安全问题(同步代码块 锁)
一。多线程
1.1并发与并行:
并发:两个或者两个以上的事件,同一段时间内发生
并行:两个或者两个以上的事件,同一时刻发生
1.2进程与线程:
进程:一个内存中运行的应用程序
线程:进程中一个执行单元 复制当前进程中程序的执行 一个进程中至少有一个线程 一个进程是可以有多个线程的 这个程序可以称为多线程程序
线程调度 : jvm采用是抢式调度 没有分时调度
1.3主线程:
其实我们从刚接触Java的时候,就已经开始接触主线程了,对的,那就是我们的main方法
作为程序的入口,它也作为我们程序运行的主线程存在
1.4创建线程类 Thread类
概述: java. lang .Thread类代表线程 所有的线程对象都必须是Thread类或者它的子类
如何使用的步骤:
1,集成Thread类 并重写run方法
2,创建Thread子类的实例就是创建了线程对象
3,调用线程对象的方法start()启动线程
public class MyThread extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
1.5 Thread类 重点
getName(); 获取线程的名字
start(); 启动线程
run(); 重写run'方法
sleep(); 休眠
currenThread(); 返回对当前正在执行的线程对象的引用
public class Test { public static void main(String[] args) { MyThread mt = new MyThread(); mt.start(); new MyThread().start(); new MyThread().start(); System.out.println(Thread.currentThread().getName()); } }
1.6实现接口方式 重难点
创建线程的另一种方法就是声明实现Runnable接口的类,该类然后实现run方法
在用接口的时候我们一般要去先实现这个接口
创建多种线程的步骤:
1,创建实现Runnable
2,重写run方法
3,创建Runnable接口类的对象
4,创建Thread类对象 构造方法里面传递Runnable接口里面的实现对象
5,调用Thread类中的start方法 开启新的线程 执行run方法
那么在这里相信很多人都会这样的疑惑:我们为啥要用实现的方法区创建多线程呢?
1,一个类如果集成了Thread类,不能集成其他类
2,一个类实现了Runnable接口还可以区集成其他类
public class Demo01Runnable { public static void main(String[] args) { //3创建Runnnable接口实现类的对象 RunnableImpl ruirui = new RunnableImpl(); // 4 创建Thread类对象 构造方法中传递Runnable接口中的实现类对象 Thread t = new Thread(ruirui); // 5 调用Thread类中start 方法 开启新的线程 执行run方法 t.start(); //主线程开启 for(int i= 0;i<20;i++){ System.out.println(Thread.currentThread().getName()+"--->"+i); } } }
二。线程安全
当我们使用多个线程访问同一个资源 ,并且多个线程中对资源有写的操作 就容易出现线程安全问题 解决 java中提供同步来解决 synchronized
那么相对的会有三种解决方法:
1,同步代码块
2,同方法
3,Lock锁
就拿我们买票的现实生活案例来说,一个窗口买票属于单线程,那么多个窗口卖票是不是就是多线程呢?
先看下我们如何区实现:
首先我们会创建一个类:
public class RunnableImpl implements Runnable{ // 定义共享资源 线程不安全 private int ticket = 100; // 线程任务 卖票 @Override public void run() { while(true){ if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //卖票操作 System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票"); ticket--; } } } }
然后创建线程:
public class Demo01PayTicket { public static void main(String[] args) { RunnableImpl r = new RunnableImpl(); // 创建3个线程 Thread t = new Thread(r); Thread t1 = new Thread(r); Thread t2= new Thread(r); t.start(); t1.start(); t2.start(); } }
这里我们以三线程为例
可是卖票容易出现一个问题,可能这个窗口卖的票,其他窗口也买,那么出现这个问题我们怎么解决?
二。1同步代码块的方法
它的步骤分为三步:
1,建立锁对象 任意对象
2,必须保证多个线程使用的是同一个锁对象
3,把{}只让一个线程进
public class RunnableImpl implements Runnable{ // 定义共享资源 线程不安全 private int ticket = 100; //在成员位置创建一个锁对象 Object obj = new Object(); // 线程任务 卖票 @Override public void run() { while(true){ //建立锁对象 synchronized (obj){ if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //卖票操作 System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票"); ticket--; } } } } }
二。2同方法:
它的步骤是:
1,创建一个方法 修饰符添加synchronized
2,把访问了共享数据的代码放进方法中
3,调用同步方法
public class RunnableImpl implements Runnable{ // 定义共享资源 线程不安全 private int ticket = 100; // 线程任务 卖票 @Override public void run() { while(true){ payTicket(); } } public synchronized void payTicket(){ if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //卖票操作 System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票"); ticket--; } } }
二。3Lock锁
它的步骤是:
1,在成员位置 创建Lock接口的实现类 ReentrantLock
2,在可能会出现代码的问题前面 调用lock方法
3,在可能会出现代码的问题后面,调用unlock方法 释放锁对象
public class RunnableImpl implements Runnable{ // 定义共享资源 线程不安全 private int ticket = 100; // 线程任务 卖票 // 1 在成员的位置 创建Lock接口的实现类 ReentrantLock Lock l = new ReentrantLock(); @Override public void run() { while(true){ // 2 在可能会出现代码的问题前面 调用lock 方法 l.lock(); if(ticket>0){ try { Thread.sleep(100); //卖票操作 System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票"); ticket--; } catch (InterruptedException e) { e.printStackTrace(); }finally { //3 在可能会出现代码的问题后面 调用unlock() 释放锁对象 l.unlock(); } } } } }
三。线程状态
概述:当线程被创建后,不是--启动就进入执行状态
1,New线程刚被创建 但是未被启动
2,Runnable可运行JVM里的状态
3,Blocked阻塞
4,waiting无线等待一个线程在等待另外一个线程唤醒
5,TimeWaiting计时等待
6,Teminated被终止因为run()正常退出而死亡