文档章节

多线程实现方式

scooplol
 scooplol
发布于 2017/08/14 14:52
字数 1521
阅读 61
收藏 0

进程与线程

进程是程序在处理机中的一次运行。一个进程既包括其所要执行的指令,也包括了执行指令所需的系统资源,不同进程所占用的系统资源相对独立。所以进程是重量级的任务,它们之间的通信和转换都需要操作系统付出较大的开销。

线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己基本上不拥有系统资源,但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。所以线程是轻量级的任务,它们之间的通信和转换只需要较小的系统开销。

Java支持多线程编程,因此用Java编写的应用程序可以同时执行多个任务。Java的多线程机制使用起来非常方便,用户只需关注程序细节的实现,而不用担心后台的多任务系统。

Java语言里,线程表现为线程类。Thread线程类封装了所有需要的线程操作控制。在设计程序时,必须很清晰地区分开线程对象和运行线程,可以将线程对象看作是运行线程的控制面板。在线程对象里有很多方法来控制一个线程是否运行,睡眠,挂起或停止。线程类是控制线程行为的唯一的手段。一旦一个Java程序启动后,就已经有一个线程在运行。可通过调用Thread.currentThread方法来查看当前运行的是哪一个线程。

线程创建的两种方法

JAVA中创建线程可以通过继承Thread类和实现Runnable接口来创建一个线程。Runnable方式可以避免Thread 方式由于JAVA单继承特性带来的缺陷。Runnable的代码可以被多个线程(Thread实例)共享,适合于多个线程处理同一资源的情况。

方式一:继承Thread

class MyThread extends Thread{
   private int ticketsCont=5; //一共有5张火车票

    private String name; //窗口, 也即是线程的名字

    public MyThread(String name){
        this.name=name;
    }

    @Override
    public void run(){
        
        while(ticketsCont>0){
            ticketsCont--; //如果还有票,就卖掉一张票
            System.out.println(name+"卖掉了1张票,剩余票数为:"+ticketsCont);
        }
        
    }

}

public class TicketsThread
{
    public static void main(String args[]){
        
        //创建三个线程,模拟三个窗口卖票
        MyThread mt1=new MyThread("窗口1");
        MyThread mt2=new MyThread("窗口2");
        MyThread mt3=new MyThread("窗口3");

        //启动三个线程,也即是窗口,开始卖票
        mt1.start();
        mt2.start();
        mt3.start();

    }
}

方式二:实现Runnable接口

class MyThread2 implements Runnable
{
    private int ticketsCont=1000; //一共有5张火车票
    
    @Override
    public void run(){
        
            
            while(true){
                 synchronized(this){
                    if(ticketsCont<=0){
                        break;
                    }
                    ticketsCont--; //如果还有票,就卖掉一张票
                    
                    System.out.println(Thread.currentThread().getName()+"卖掉了1张票,剩余票数为:"+ticketsCont);
                    
                    /*try{
                        Thread.sleep(50);  //通过阻塞程序来查看效果
                    }
                    catch(Exception e){
                        System.out.println(e);
                    }*/

                }
            }
        
    }



    /*@Override  //不加同步锁
    public void run(){
        while(ticketsCont>0){
            ticketsCont--; //如果还有票,就卖掉一张票
            System.out.println(Thread.currentThread().getName()+"卖掉了1张票,剩余票数为:"+ticketsCont);
        }
    }*/
}

public class TicketsRunnable
{
    public static void main(String args[]){
        
        MyThread2 mt=new MyThread2();
        //创建三个线程来模拟三个售票窗口
        Thread th1=new Thread(mt,"窗口1");
        Thread th2=new Thread(mt,"窗口2");
        Thread th3=new Thread(mt,"窗口3");

        //启动三个线程,也即是三个窗口,开始卖票
        th1.start();
        th2.start();
        th3.start();
        

    }
}

  • 创建:新建一个线程对象,如Thread thd=new Thread()
  • 就绪:创建了线程对象后,调用了线程的start()方法(此时线程知识进入了线程队列,等待获取CPU服务 ,具备了运行的条件,但并不一定已经开始运行了)
  • 运行:处于就绪状态的线程,一旦获取了CPU资源,便进入到运行状态,开始执行run()方法里面的逻辑
  • 终止:线程的run()方法执行完毕,或者线程调用了stop()方法,线程便进入终止状态
  • 阻塞:一个正在执行的线程在某些情况系,由于某种原因而暂时让出了CPU资源,暂停了自己的执行,便进入了阻塞状态,如调用了sleep()方法

线程的分类

  • 用户线程:运行在前台,执行具有的任务程序的主线程,连接网络的子线程等都是用户线程
  • 守护线程:运行在后头,为其他前台线程服务。一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作。可以通过调用Thread类的setDaemon(true)方法来设置当前的线程为守护线程,该方法必须在start()方法之前调用,否则会抛出 IllegalThreadStateException异常。在守护线程中产生的新线程也是守护线程。不是所有的任务都可以分配给守护线程来执行,比如读写操作或者计算逻辑。

 

场景:一个主线程,一个守护线程,守护线程会在很长一段时间内向本地文件中写入数据,主线程进入阻塞状态等待用户的输入,一旦确认了用户的输入阻塞就会解除掉,主线程继续运行直到结束,守护线程也会随虚拟机一同结束。

import java.io.*;
import java.util.Scanner;

class Daemon  implements Runnable
{
    @Override
    public void run(){
        System.out.println("进入守护线程");
        try{
            writeToFile();
        }
        catch(Exception e){
            e.printStackTrace();
        }

        System.out.println("退出守护线程");
    }


    private void writeToFile() throws Exception{
            File filename=new File("F:/慕课网(imooc)/细说多线程之Thread VS Runnable/daemon.txt");
            OutputStream os=new FileOutputStream(filename,true);
            int count=0;
            while(count<999){
                os.write(("\r\nword"+count).getBytes());
                System.out.println("守护线程"+Thread.currentThread().getName()+"向文件中写入word"+count++);
                Thread.sleep(1000);
            }
    }
}

public class DaemonThreadDemo
{
    public static void main(String args[]){
        System.out.println("进入主线程"+Thread.currentThread().getName());
        Daemon daemonThread=new Daemon();
        Thread thread =new Thread(daemonThread);
        thread.setDaemon(true);
        thread.start();

        Scanner sc=new Scanner(System.in);
        sc.next();

        System.out.println("退出主线程"+Thread.currentThread().getName());

        
    }
}

总结

建议使用Runnable这种方式创建线程。 程序中的同一资源指的是同一个Runnable对象。安全的卖票程序中需要加入同步synchronized。

本文转载自:http://www.cnblogs.com/Li-Cheng/p/4332179.html

scooplol
粉丝 17
博文 103
码字总数 205785
作品 0
南充
程序员
私信 提问
java实现多线程两种基本方式

我们在开发当中经常会使用到多线程,这里我们来写两个小案例通过最基本的两种方式继承Thread类或实现Runnable接口来实现一个多线程。 继承Thread类 我们可以通过继承Thread类,并重写run()方...

王子城
2018/11/13
47
0
这是一份全面 & 详细的Android多线程知识总结指南

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。 目录 1. 多线程基础知识 在了解Android多线程实现...

Carson_Ho
06/26
0
0
Android:关于多线程的总结知识都在这里了!

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。 目录

Carson_Ho
05/22
0
0
Java多线程基础篇(02)-多线程的实现

1.概要 JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后...

kukudeku
2016/09/19
90
0
JAVA多线程实现的三种方式

最近在做代码优化时学习和研究了下JAVA多线程的使用,看了菜鸟们的见解后做了下总结。 1.JAVA多线程实现方式 JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorS...

JasonO
2016/03/08
145
0

没有更多内容

加载失败,请刷新页面

加载更多

正则表达式匹配

请实现一个函数用来匹配包括 '.' 和 '*' 的正则表达式。模式中的字符 '.' 表示任意一个字符,而 '*' 表示它前面的字符可以出现任意次(包含 0 次)。 在本题中,匹配是指字符串的所有字符匹配...

Garphy
今天
7
0
Laravel 5.1的多路由文件的配置

默认的路由配置文件只有一个, \app\Http\routes.php。 在同一个文件中写路由容易起冲突,文件会越来越大,就需要定义多个路由文件。 找到加载\app\Http\routes.php的文件, 打开\app\Provid...

mdoo
今天
5
0
Hibernate 5 开始使用指南前言

同时在面向对象软件和关系型数据库进行工作,可能会非常复杂和费时。数据在对象和数据库之间可能会不一致,然后导致开发成本会非常高。 Hibernate 是一个针对 Java 环境的对象关系映射(Obj...

honeymoose
今天
6
0
聊聊nacos ServiceManager的UpdatedServiceProcessor

序 本文主要研究一下nacos ServiceManager的UpdatedServiceProcessor ServiceManager.init nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java @Compone......

go4it
今天
7
0
正则表达式的使用(QQ格式的判断与空格的切割)

//正则表达式的使用 public static void main(String[] args) throws IOException, ClassNotFoundException { //test1("123456"); test2("-1 99 kk"); } /** * ......

zhengzhixiang
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部