ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

多线程

2020-06-28 13:02:29  阅读:201  来源: 互联网

标签:Thread start 线程 new ticket 多线程 public


生活中的多线程

  如果把进程比作一个高速公路的收费站,那么这个地点的多个收费匝道就可以比作线程。如果把行政大厅比作一个进程,那么每一个办事窗口都是一个线程。

实现多线程的方法

  1.通过继承Thread实现多线程:Thread类存放在Java.lang类库里,eclipse默认加载。用户想要实现多线程,必须定义自己继承于Thread的子类,同时覆写Thread的run方法

package java_thread;

class TestThread extends Thread{
    public void run() {
        for(int i=0;i<5;i++) {
            System.out.println("TestThread正在运行");
            try {
                Thread.sleep(1000);
            }catch(InterruptedException e) {
                //InterruptedException表示中断异常类,Thread.slepp()和Object.wait()都可能抛出这类中断异常
                e.printStackTrace();
            }
        }
    }
}


public class ThreadDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new TestThread().start();
        for(int i = 0;i<5;i++) {
            System.out.println("main线程正在运行");
            try {
                Thread.sleep(1000);
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

  2.通过实现Runnable接口实现多线程:如果一个类已经继承了其他类,那么这个类就不能再继承Thread类。如果这个类又想采用多线程技术,那么只能实现Runnable接口来创建线程。

需要注意激活一个线程,要使用Thread类的start()方法,通过查找Java开发文档发现,在Runnable接口内,仅只有一个run方法,该方法代表的只是算法。要通过Thread类的一个构造方法:

public Thread(Runnable target)将Runnable接口实例化对象,然后调用start()方法来激活线程。

package java_thread;


class TestThread2 implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i =0 ; i<5;i++) {
            System.out.println("TestThread线程正在运行");
            try {
                Thread.sleep(1000);
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


public class RunnableThread {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        TestThread2 newth = new TestThread2();
        new Thread(newth).start();//使用Thread类的start方法启动线程
        for(int i = 0;i<5;i++) {
            System.out.println("main线程正运行");
            try {
                Thread.sleep(1000);
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

 到这里,对于Thread和Runnable之间的关系,可能就已经很清晰了,Runnable可以通过Thread去实例化,那么这两种多线程之间的比较:

  通过查阅jdk文档,他们之间有这种关系:public class Thread extends Object implements Runnable

  所以在本质上,Thread类是Runnable接口众多的实现子类中的一个,它和我们自己写一个Runnable接口的实现类地位差不多,只不过Thread是官方提供的设计罢了。

下面模拟一个使用Thread实现多线程售票系统的不断改进:

package java_thread;

class Test_Thread extends Thread{
    private int ticket = 5;
    @Override
    public void run() {
        while(ticket > 0) {
            System.out.println(Thread.currentThread().getName()+"出售票"+ticket);
            ticket -= 1;
        }
    }

}

public class Thread_SaleDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
            Test_Thread newth = new Test_Thread();//一个线程对象只能启动一次
            newth.start();
            newth.start();
            newth.start();
            newth.start();
            
    }

}

改进:

package java_thread;

class Test_Thread extends Thread{
    private int ticket = 5;
    @Override
    public void run() {
        while(ticket > 0) {
            System.out.println(Thread.currentThread().getName()+"出售票"+ticket);
            ticket -= 1;
        }
    }

}

public class Thread_SaleDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
            new Test_Thread().start();
            new Test_Thread().start();
            new Test_Thread().start();
            new Test_Thread().start();
            
    }

}

这段代码出现卖出票数多于拥有票数的情况,再次改进:(1.使用static让ticket变量公有  2.换成实现Runnable接口的方法)

1.
package java_thread; class Test_Thread extends Thread{ private static int ticket = 5; @Override public void run() { while(ticket > 0) { System.out.println(Thread.currentThread().getName()+"出售票"+ticket); ticket -= 1; } } } public class Thread_SaleDemo { public static void main(String[] args) { // TODO Auto-generated method stub new Test_Thread().start(); new Test_Thread().start(); new Test_Thread().start(); new Test_Thread().start(); } }
2.
package java_thread; class Test_Thread implements Runnable{ private static int ticket = 5; @Override public void run() { while(ticket > 0) { System.out.println(Thread.currentThread().getName()+"出售票"+ticket); ticket -= 1; } } } public class Thread_SaleDemo { public static void main(String[] args) { // TODO Auto-generated method stub Test_Thread newth = new Test_Thread(); new Thread(newth).start(); new Thread(newth).start(); new Thread(newth).start(); new Thread(newth).start(); } }

但是这也产生了一票多卖的现象,当ticket=1,的时候,被多个进程同时看到,满足条件,将票卖了出去,ticket理应减1,但是还没有来得及更新,当前线程的运行时间片就到了,必须退出cpu,然其他线程执行,而其他线程看到的ticket依然是旧状态。

这在多线程运行环境中,ticket属于典型的临界资源,而下面这部分代码属于临界区

private static int ticket = 5;
    @Override
    public void run() {

通过上面的例子,实现Runnable接口相对于继承Thread来说,有几点优势:
  1.避免了由于Java单继承带来的局限性

  2.可使多个线程共享相同的资源,达到资源 共享的目的

 

线程的状态:
  每个线程都有

    1.创建态(new):初始状态,线程已经被构建,但尚未启动,即还没有被调用start()方法

    2.运行态(Runnable):正在JVM执行的线程处于这种状态,将操作系统中的就绪(ready)和运行(running)状态统称为运行态

    3.阻塞态(blocked):受阻塞,并等待于某个监视器

    4.无线等待状态(waiting):无限期的等待,表明当前线程需要等待其他线程执行某一个特定操作(通知或中断)

    5.超时等待状态(timed_waiting):与waiting状态不同,可以在指定的等待时间后,自行返回

    6.终止态(terminated):表示当前线程已经执行完毕    

  线程的操作方法:

    1.getName() 取得线程名称  2.setName() 设置线程名称  3.currentThread()返回该方法的线程实例  4.isAlive() 判断线程是否启动

  start()和run()方法的不同:

    1.start():它的作用是启动一个新线程,调用它才能真正实现多线程,无需等待run方法体的执行完毕,而是直接执行start()下面的代码。start的调用,使主线程创建了一个新线程,并使得这个线程进入“就绪状态”,如果主线程执行完start()语句后,cpu时间片还没用完,就会接着运行start()后面的语句。一旦新的线程得到时间片,就开始执行run()方法,一旦run()方法执行结束,线程随即停止。

    2.run():只是一个普通的覆写方法。

守护线程:
    在JVM中,线程分为两类:用户线程和守护线程。

    用户线程:前台线程(一般线程),对Java程序来说,只要还有一个用户线程在运行,进程就不会结束。

    守护线程(daemon):后台线程。守护其他线程的线程,通常运行在后台,为用户程序提供一种通用服务的线程。当线程中只剩下守护线程的时候,JVM就会自动退出,反之如果还有任何用户线程在,JVM就不会退出。普通用户线程只有调用setDeamon(true)后,才能转成守护线程。

线程的联合:
    join()方法的功能是把指定的线程加入到当前线程,从而实现将两个交替执行的线程,合并为顺序执行的线程。除了无参join()方法外,还有带参的join方法join(long millis)精确到毫秒,作用是指定最长等待时间,如果超过指定时间,合并的线程还没有结束,就直接分开。

package java_thread;

class Thread_Test0 implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        int i =0;
        for(int x =0; x<5;x++) {
            try {
                Thread.sleep(1000);
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"----->"+i);
            i+=1;
        }
    }
    
}

public class ThreadJoin {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread_Test0 t = new Thread_Test0();
        Thread pp = new Thread(t);
        pp.start();
        int flag = 0;
        for(int x = 0; x<5 ;x++) {
            if(flag == 3) {
                try {
                    pp.join();    
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main thread"+x);
            flag += 1;
        }
    }

}

线程的特点:
  1.如果一个进程只有后台,则这个进程就会结束。

  2.同步代码块和同步方法锁的是对象,而不是代码。

  3.每一个已经被创建的进程在结束之前均会处于就绪,运行,阻塞状态之一。

 

标签:Thread,start,线程,new,ticket,多线程,public
来源: https://www.cnblogs.com/hzyang/p/13201976.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有