线程浅解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39088514/article/details/74087213

线程

线程的介绍

  1. 什么是线程:说起线程,我们就不得不提进程。什么是进程,进程简单的来说就是cpu中运行的一个程序,每个进程有不同的端口。而线程则是进程中的处理控制流程。

    • 一个进程可以拥有多个线程
    • 一个进程中的线程共享相同的内存单元/内存地址空间可以访问相同的变量和对象,而且它们从同一堆中分配对象通信、数据交换、同步操作
    • 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息传递的速度也更快。
  2. 线程与进程的区别

  3. 进程的运行机制:cpu为进程分配了内存和资源,而线程之间抢进程给他们分配的资源,谁抢到谁执,并非一起执行。

线程的创建和使用

  • 线程关键字:Thread
  • 线程的状态:线程有新生态 运行态 阻塞态 终止态

    线程在调用start方式时,线程则是处在就绪状态。通过调用wait或者sleep方法,线程则到了阻塞状态。当阻塞状态过去之后,并不是直接进入运行状态,而是进行到就绪状态。最后则终止

    1. 线程的优点:多个线程去执行相同或者不同的代码块,可以大大提高代码运行速度和解决程序的卡顿等等
  • 线程的创建

    • 线程通过继承THread或者实现Runbale两种方法去实现,它们都需要重写其中的run方法,方法run称为线程体。main方法为主线程,其余称为子线程,调用的时候先调用主线程,再调用子线程。

代码如下:

 public class ThreadDemo {
   public static void main(String[] args) {
    System.out.println("我是主线程");
  new   Thread(new Thread01()).start();
  new   Thread(new Thread02()).start();
}
}
class Thread01 extends Thread{
    @Override
    public void run() {
        System.out.println("我是继承Thread的线程");
        super.run();
    }
}
class Thread02 implements Runnable{

    @Override
    public void run() {
        System.out.println("我是实现Runbale接口的线程");
    }

}

运行结果:

 我是主线程
我是继承Thread的线程
我是实现Runbale接口的线程
  • 从运行结果,我们可以看到,主线程是最先执行的。
  • 线程的休眠:

代码如下:

public class ThreadDemo2 {
public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Thread001());
        thread.start();
       for(int i=0;i<3;i++){
           Thread.sleep(1000);
           System.out.println("正在休眠的第"+i+"秒");
       }
    }
}
class Thread001 implements Runnable{

    @Override
    public void run() {
        System.out.println("子线程");
    }

}

运行结果:

子线程
正在休眠的第0秒
正在休眠的第1秒
正在休眠的第2秒
  • 多线程
    • 现在我们模拟一个火车票站点售票,5个窗口同时售票。票数总数为100张。我们来看一下怎么实现。

代码如下:

public class ThreadDemo3 {
public static void main(String[] args) {
        Thread3_1 thread3_1 = new Thread3_1();
        for (int i = 0; i < 5; i++) {

            new  Thread(thread3_1,"窗口"+(i+1)).start();
        }
    }
}
class Thread3_1 implements Runnable{
int count=100;
    @Override
    public void run() {
        while(count>0){
        if(count>0){
            System.out.println(Thread.currentThread().getName()+"正在售卖第"+count--+"张票");
        }
    }
        }

}

运行结果:

窗口1正在售卖第100张票
窗口1正在售卖第99张票
窗口1正在售卖第98张票
窗口1正在售卖第97张票
窗口1正在售卖第96张票
窗口1正在售卖第95张票
窗口1正在售卖第94张票
窗口1正在售卖第93张票
窗口1正在售卖第92张票
窗口1正在售卖第91张票
窗口1正在售卖第90张票
窗口1正在售卖第89张票
窗口1正在售卖第88张票
窗口1正在售卖第87张票
窗口1正在售卖第86张票
窗口1正在售卖第85张票
窗口1正在售卖第84张票
窗口1正在售卖第83张票
窗口1正在售卖第82张票
窗口1正在售卖第81张票
窗口1正在售卖第80张票
窗口1正在售卖第79张票
窗口1正在售卖第78张票
窗口1正在售卖第77张票
窗口1正在售卖第76张票
窗口1正在售卖第75张票
窗口1正在售卖第74张票
窗口1正在售卖第73张票
窗口1正在售卖第72张票
窗口1正在售卖第71张票
窗口1正在售卖第70张票
窗口1正在售卖第69张票
窗口1正在售卖第68张票
窗口1正在售卖第67张票
窗口1正在售卖第66张票
窗口1正在售卖第65张票
窗口2正在售卖第64张票
窗口1正在售卖第63张票
窗口2正在售卖第62张票
窗口2正在售卖第60张票
窗口1正在售卖第61张票
窗口2正在售卖第59张票
窗口1正在售卖第58张票
窗口2正在售卖第57张票
窗口1正在售卖第56张票
窗口2正在售卖第55张票
窗口1正在售卖第54张票
窗口2正在售卖第53张票
窗口5正在售卖第51张票
窗口5正在售卖第49张票
窗口2正在售卖第50张票
窗口1正在售卖第52张票
窗口1正在售卖第45张票
窗口2正在售卖第46张票
窗口5正在售卖第47张票
窗口3正在售卖第48张票
窗口5正在售卖第42张票
窗口2正在售卖第43张票
窗口1正在售卖第44张票
窗口2正在售卖第39张票
窗口5正在售卖第40张票
窗口3正在售卖第41张票
窗口5正在售卖第36张票
窗口2正在售卖第37张票
窗口1正在售卖第38张票
窗口2正在售卖第33张票
窗口5正在售卖第34张票
窗口3正在售卖第35张票
窗口5正在售卖第30张票
窗口2正在售卖第31张票
窗口1正在售卖第32张票
窗口2正在售卖第27张票
窗口5正在售卖第28张票
窗口3正在售卖第29张票
窗口5正在售卖第24张票
窗口2正在售卖第25张票
窗口1正在售卖第26张票
窗口2正在售卖第21张票
窗口5正在售卖第22张票
窗口3正在售卖第23张票
窗口5正在售卖第18张票
窗口2正在售卖第19张票
窗口1正在售卖第20张票
窗口2正在售卖第15张票
窗口5正在售卖第16张票
窗口3正在售卖第17张票
窗口3正在售卖第11张票
窗口3正在售卖第10张票
窗口3正在售卖第9张票
窗口3正在售卖第8张票
窗口3正在售卖第7张票
窗口3正在售卖第6张票
窗口5正在售卖第12张票
窗口2正在售卖第13张票
窗口1正在售卖第14张票
窗口2正在售卖第3张票
窗口5正在售卖第4张票
窗口3正在售卖第5张票
窗口2正在售卖第1张票
窗口1正在售卖第2张票
  • 通过以上代码,我们发现了线程的名字和线程的获取,现在我们来看一下线程的API再进行下面的分析。
    • 构造方法:
    • 方法:

      我们可以从构造方法中看到,可以传去Runable实体和线程的名字。从运行结果来看,我们看到线程并不是按顺序来运行的,而是像上文所说的去争夺资源运行。
    • 多线程一起共享一个代码块的时候,从运行结果中看到会出现很多问题,我们卖票程序出现了丢票的情况或者重复票的情况,这是不能允许的。因为线程去访问的时候,并不是有规律的去运行代码块,我们如果能够做到让线程挨个去运行代码块,这个问题就迎刃而解了,怎么解决这个问题的。让我们往下看
    • 关于上边的问题,让我们在看一个代码。

代码如下:

public class 
ThreadDemo4 implements Runnable{
private int tick=5;
    @Override
    public void run() {
        while(true){
            if(tick>0){
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName()+"卖票:"+tick--);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }       
    }
public static void main(String[] args) {
    ThreadDemo4 ti = new  ThreadDemo4();
    new Thread(ti).start();
        new Thread(ti).start();
        new Thread(ti).start();
        new Thread(ti).start();

    }
}

运行结果:

Thread-0卖票:5
Thread-3卖票:2
Thread-2卖票:3
Thread-1卖票:4
Thread-2卖票:1
Thread-1卖票:0
Thread-3卖票:1
Thread-0卖票:-1

* -1 显然不是我们要的,这就需要线程的安全性了

线程的安全性(同步)
  • 同步:通俗的来说就是让线程一个一个的去访问代码块,怎么去做到呢,有两种方法。
  • 关键字synchronized 它可以是一个修饰符去修饰在类前,也可以在关键代码前使用synchronized(this){ 关键代码块 }

线程的死锁

  • 死锁:上文我们说到,要线程一个一个去完成代码块,这就是我们的死锁,当符合条件的时候,线程休眠或者唤醒,通过boolean去控制。这就是我们的死锁。

  • 需要用到的方法:

结束

           -------2017年7月2日00:12:17    syf

猜你喜欢

转载自blog.csdn.net/qq_39088514/article/details/74087213