Java中的多线程

进程跟线程的概念


进程:

  • 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。


线程:

  • 线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。



单线程
  • 单线程也可以理解为是串行任务:一次只执行一个
/**
 * 普通类
 * 模拟串行任务
 * 原理:执行完一个方法之后才能执行另一个方法
 * @author LingDu
 */
public class Demo {

    public static void test1() {
        for (int i = 0; i < 5; i++) {

            System.out.println("不快乐!" + i);
        }
    }

    public static void test2() {
        System.out.println("------快乐!");
    }

    public static void main(String[] args) {

        test1();
        test2();

    }
}


执行完第一个方法之后才会执行第二个。

1



多线程
  • 多线程可以理解为是并行:一次执行多个(原理还是cpu分时)


使用多线程常用的方法:



继承Thread类


  • 重写run()方法
/**
 * 通过继承得到一个多线程的类。
 * 多线程可以并行
 * @author Administrator
 *
 */
public class RichMan extends Thread {


    @Override
    public void run() {

        for(int i =0;i<5;i++){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(this.getName() +":" +  i);
        }
    }

    /**
     * 空的构造方法
     */
    public RichMan(){

    }

    /**
     * 指定线程名称的构造方法
     * @param name
     */
    public  RichMan(String name){
        this.setName(name);
    }



    public static void main(String[] args) {
        //亲儿子
        RichMan wangsicong = new RichMan("亲儿子");
        wangsicong.start();

        //私生子
        RichMan otherChild = new RichMan("私生子");
        otherChild.start();

    }
}

2




实现Runnable接口


  • 重写run()方法
/**
 * 实现接口 Runnable
 * implements Runnable
 * 重写run()方法
 * @author LingDu
 *
 */
public class RunnableImplDemo implements Runnable {

    @Override
    public void run() {

        for(int i = 0;i<10; i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(i);
        }
    }

    public static void main(String[] args){
        RunnableImplDemo t1 = new RunnableImplDemo();
        new Thread(t1).start();
    }
}

3




匿名内部类实现多线程

/**
 * 匿名内部类实现 new Runnable() 
 * 重写run()方法
 * @author LingDu
 */
public class RunnableImplDemo2 {

    public static void test1() {
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(500);
                        System.out.println(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t1.start();
    }

    public static void main(String[] args) {
        test1();
    }
}

4



实战



多线程实现并发访问


之前我发过一篇使用Socket 套接字 来实现的服务端的程序:

http://blog.csdn.net/gfd54gd5f46/article/details/54987510


实现的功能很单一,每次只能连接一个用户,现在我们就利用多线程来创建一个可以多人连接的Socket服务端



功能:

  • 模拟自动回复机器人,可以同时多人连接


需求:

  • 1、允许多个客户端连接上来
  • 2、接收客户端的连接请求。
  • 3、当客户端连接上我们的端口之后发送欢迎语
  • 4、当客户端发送一个消息给服务端时,可以自动回复信息


SocketThread类,继承自Thread ,用于实现功能

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

/**
 * 2017.2.13
 * SocketThread类
 * 功能:接收用户信息并且自动回复信息
 * @author LingDu
 */
public class SocketThread extends Thread{

    Socket socket = null;

    /**
     * 带参的构造方法
     * 传入一个Socket对象
     * @param socket
     */
    public SocketThread(Socket socket) {
        super();
        this.socket = socket;
    }

    /**
     * 重写的run()方法
     */
    @Override
    public void run() {
        userConnection();
    }


    /**
     * 用户连接的方法
     */
    public void userConnection(){
        try {
            //打印出连接的用户
            System.out.println("连接一个用户:" + socket.getInetAddress());
            //拿到用户的输出流
            PrintWriter pw = new PrintWriter(socket.getOutputStream());
            //用户连接上来后先发送欢迎语
            pw.println("欢迎光临!");
            pw.flush();
            //拿到用户的输入流
            Scanner scanner = new Scanner(socket.getInputStream());
            //如果有下一行数据
            while(scanner.hasNextLine()){
                //拿到用户发送过来的消息
                String msg = scanner.nextLine();
                //如果是 “exit” 
                if("exit".equalsIgnoreCase(msg)){
                    //跳出循环
                    break;
                }
                //返回一个自动处理过的消息
                String reutrnMsg = ServerSocketDemo.getRetuenMsg(msg);
                //将消息返回给用户
                pw.println(reutrnMsg);
                //刷新
                pw.flush();
            }
            socket.close();
            pw.close();
            scanner.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


ServerSocketDemo类,用于开启服务

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class ServerSocketDemo {
    /**
     * 开启程序
     * 功能:允许多人连接
     */
    public static void threadStart(){
        ServerSocket serverSocket = null;
        try {
            //创建服务端端口8888
            serverSocket = new ServerSocket(8888);
            System.out.println("服务已启动!");
            //获取用户的连接
            while(true){
                Socket socket = serverSocket.accept();
                //创建SocketThread对象,将连接传入进去
                SocketThread st = new SocketThread(socket);
                //启动线程
                st.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 这里模拟自动回复机器人的功能
     * 1、传入用户发送过来的消息
     * 2、简单判断之后将结果返回
     * @param msg 用户的消息
     * @return returnMsg
     */
    public static String getRetuenMsg(String msg){
        if(msg == null){
            msg = "";
        }
        String returnMsg = "";

        //如果消息中包涵 “在吗” 字段
        if(msg.contains("在吗")){
            returnMsg = "亲,所有商品都有货,小二24小时在线";

        }else if(msg.contains("发货")){
            returnMsg = "亲,我们立即发货";

        }else if(msg.contains("包邮")){
            returnMsg = "亲,我们所有商品全部包邮,除了西藏/新疆";

        }else{
            returnMsg = "亲,你大概不是在玩真的";
        }

        return returnMsg;
    }


    public static void main(String[] args){
        threadStart();
    }
}

5



使用telnet进行连接测试

  • 此时服务端检测到一个用户,会开启一个线程,并将欢迎语发送给客户端

12



客户端收到欢迎语

6



接下来测试一个自动回复的功能

7



多人连接的时候会创建多个线程

8


这样一个简单的多并发程序就做好了


模拟多人抢红包程序


功能:

  • web端:创建红包网页,用户访问时返回一个1-10元的随机金额
  • java 程序:利用多线程模拟多个用户访问页面,拿到返回的随机金额


Web端

  • 创建一个 Dynamic Web Project 项目

9



Servlet 容器:

    /**
     *  RP.java
     *  生成一个随便返回到页面
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        Math.random();
        int max=10;
        int min=1;
        Random random = new Random();

        int s = random.nextInt(max)%(max-min+1) + min;
        response.getWriter().append(s+"");
    }


开启Tomcat服务器

URL地址:http://192.168.20.68:8080/firstweb/RP

10



Java程序

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Scanner;

/**
 * 2017.2.13
 * 使用多线程获取红包
 * @author LingDu
 *
 */
public class ThreadGetRedPackage extends Thread {


    @Override
    public void run() {
        System.out.println(getRedPackage());
    }

    // 无参的构造方法
    public ThreadGetRedPackage() {
        super();
    }

    // 带参数的构造方法,传入一个名字
    public ThreadGetRedPackage(String name) {
        super(name);
    }

    // 返回网页内容
    public String getRedPackage() {
        String returnContent = "";
        try {
            URL url = new URL("http://192.168.20.68:8080/firstweb/RP");
            try {
                Scanner sc = new Scanner(url.openStream());
                String content = "";
                while (sc.hasNextLine()) {
                    content += sc.nextLine();
                }

                returnContent = this.getName() + "------>抢到:" + content + "元红包";
                sc.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return returnContent;
    }

    public static void main(String[] args) {
        //创建三个线程同时访问红包页面
        ThreadGetRedPackage t1 = new ThreadGetRedPackage("t1");
        ThreadGetRedPackage t2 = new ThreadGetRedPackage("t2");
        ThreadGetRedPackage t3 = new ThreadGetRedPackage("t3");

        t1.start();
        t2.start();
        t3.start();

        //主线程再模拟5个机器人
        for (int i = 0; i < 5; i++) {
            ThreadGetRedPackage robot = new ThreadGetRedPackage("机器人" + i);
            robot.start();
        }
    }
}

11


这样就实现了一个利用多线程从网上拿红包的程序



当然,程序是不完整的
有关多线程的更多知识(例如线程同步、线程安全、死锁问题等…)都会在后续文章中一 一详解



总结:

多线程的优缺点

优点:

  • 1、 资源利用率更好
  • 2、 程序响应更快

缺点:

  • 1、线程太多会降低系统的运行性能

多线程应用场景
  • 1、压力测试时,会用到多线程。
  • 2、服务器编程时,会用到多线程。
  • 3、使用监听器时,可能会用到多线程。
  • 4、跑JOB时,可能会用到多线程。

那些地方适合使用多线程
  • 1、耗时或大量占用处理器的任务阻塞用户界面操作。
  • 2、各个任务必须等待外部资源 (如远程文件或 Internet连接)。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java线程实现的原理主要是通过线程对象的创建和启动来实现的。Java实现多线程的方式有四种:继承Thread类、实现Runnable接口、实现Callable接口、使用线程池。下面分别介绍这四种方式的实现原理: 1. 继承Thread类 继承Thread类是实现多线程的一种方式,它的实现原理是创建一个继承自Thread类的子类,并重写run()方法,在run()方法编写线程执行的代码。然后创建该子类的对象,并调用start()方法启动线程。 2. 实现Runnable接口 实现Runnable接口是实现多线程的另一种方式,它的实现原理是创建一个实现了Runnable接口的类,并实现run()方法,在run()方法编写线程执行的代码。然后创建该类的对象,并将其作为参数传递给Thread类的构造方法,最后调用start()方法启动线程。 3. 实现Callable接口 实现Callable接口是实现多线程的一种方式,它的实现原理是创建一个实现了Callable接口的类,并实现call()方法,在call()方法编写线程执行的代码。然后创建该类的对象,并将其作为参数传递给FutureTask类的构造方法,最后调用start()方法启动线程。 4. 使用线程池 使用线程池是实现多线程的一种方式,它的实现原理是创建一个线程池对象,并将任务提交给线程池执行。线程池会自动管理线程的创建和销毁,从而避免了频繁创建和销毁线程的开销。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值