##什么是线程?

在我们开始今天的线程之前,我们先来几道干货,是什么呢?就是我们一般取公司面试可能会被问道的面试题:

  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()正常退出而死亡

原文地址:https://www.cnblogs.com/liurui-bk517/p/10932487.html