关于多线程

关于多线程:
多线程的意思其实就是可以同时执行多个程序,并且互相之间不受影响;不过先后顺序都不确定;
单线程的缺点:虽然可以用while循环保证服务端可以一直服务,但是每一次只能服务一个用户,且read()方法是阻塞方法,如果这个已建立连接的用户一直没有发消息,那么连接就会一直阻塞在这,直到用户发消息,才会往下走,而只有这个连接走完了才会进入下一次连接;
并且,如果某一次连接出现异常,会中断整个服务端;
有一个接口Runnable;
public interface Runnable{
public void run(){
}//Thread会自动调用这个方法
}
有一个类Thread;
public class Thread{
private Runnable r;

public Thread(Runnable r){
    this.r = r;
}
public void start(){
    r.run();
}

}

多线程实际上调用的就是Thread类里的start方法;
而这个方法需要一个r类型的对象来调用它的run方法,所以想要实现多线程就要有一个类实现Runnable方法,并且实现run这个方法,然后new一个Thread对象,调用它的有参构造方法,传入这个实现类的对象,再让Thread对象调用自身的Start方法即可;

简单案例:
//demo1这个类是Runnable的实现类,并且实现了run这个方法;
public class Demo1 implements Runnable {
private String name;

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


public void setName(String name) {
    this.name = name;
}

@Override
public void run() {
    for (int i = 0; i < 6; i++) {
        System.out.println("啊....."+name);
        //run方法中是不能传参数的,为了每个线程执行时可以打出来的信息不一样,我们可以
        //给demo1这个类写成员变量,然后在run的实现逻辑中与这个成员变量关联起来;
    }

}

}
//new几个Demo1的对象
public class Demo1Test {

public static void main(String[] args) {

    Demo1 demo11 = new Demo1("张三");

    Demo1 demo12 = new Demo1("李四");

    Demo1 demo13 = new Demo1("王五");
    //只要在Demo1的构造方法中传不一样的成员变量值就可以了;



    Demo2 demo2 = new Demo2();
    //demo1.run();  // 这样调,只是用单线程普通地执行一下这个run方法而已

    // 构造一个线程,指定要执行的逻辑
    Thread thread1 = new Thread(demo11);//Thread()括号里只能传runnable对象;
    Thread thread2 = new Thread(demo12);
    Thread thread3 = new Thread(demo13);


    // 这种调用,只是按顺序进行普通的方法调用,是在一个单线程中挨个执行的
    /*thread1.run();
    thread2.run();
    thread3.run();
    thread4.run()*/

    // 将这3个线程以多线程的方式同时运行
    thread1.start();
    thread2.start();
    thread3.start();
    //运行结果是每一个线程都是同时执行的,且每一次执行顺序都不一样;


}

}
复杂案例:与socket编程结合;
//为了让服务端可以多线程服务,也就是说一次可以服务多个用户;并且每个线程不会相互影响

public class Talk implements Runnable {
Socket sc;
//将Socket作为Talk的成员变量,这样每次都可以通过构造方法出入不一样的连接,而每一个不一//样的连接也就代表了每一个不一样的客户端;

public Talk(Socket sc) {
    this.sc = sc;
}

@Override
public void run() {
    try {
    //因为输入输出流你会抛异常,而我们不能将这个异常往上抛给run方法,因为run方法中没有抛异常,如果写了就会报错;
        // 从连接中获取输入、输出流
        InputStream in = sc.getInputStream();
        OutputStream out = sc.getOutputStream();

        //收第一个问题
        byte[] b = new byte[1024];
        int num = in.read(b);
        System.out.println("收到客户端的问题1:" + new String(b,0,num));

        // 回复第一个问题
        out.write("我是宇宙无敌超级美少女战士".getBytes());

        // 接收第二个问题
        num = in.read(b);
        System.out.println("收到客户端的问题2:" + new String(b,0,num));

        // 回复第二个问题
        out.write("我18岁".getBytes());

        //每一次用完都要关流,关连接,这是在关掉与联系完了用户之间的连接
        in.close();
        out.close();
        sc.close();

    } catch (Exception e) {
        System.out.println("发生异常了.......");
    }
}

}

//
public class ThreadServerDemo {

public static void main(String[] args) throws Exception {

    ServerSocket ss = new ServerSocket(10000);//申请一个端口号
    int i=1;
    while (true) {
    //用while循环保证服务端一直在服务,并且每一次都会接收到新的连接

        Socket sc = ss.accept();//接收到连接即可进行下一步,否则一直阻塞不运行;
        System.out.println("收到连接"+i);
        //连接之后的代码里已没有read()方法,所以不会再发生阻塞,只要接收到了连接就会走下一步;
        //每次连接成功后都会创建一个talk对象,并且传入一个连接对象作为该对象的成员变量//,这样就可以实现每个talk对象的特殊化了,因为每个talk都在与不一样的用户服务;
        Talk talk = new Talk(sc);
        //每建立一次连接都会创建一个线程,这个线程只为这个连接服务,出现异常也不会影响//下一个线程
        new Thread(talk).start();
        i++;

    }

}

}
//总结,这个案例中,每一次收到连接,就会有一个线程去为这个连接服务,而服务端可以迅速进行下一次循环;

另外,每一个main方法也是一个线程,如果想让线程终止,可以用thread.sleep();括号里填毫秒数;那么线程就将会停止相应的时间再接着运行;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值